Multi Row Variable Set Interaction with Catalog form and tracking deletes (Remove All OR Remove Row)
In this article I want to share one of the frequent and complex requirement we usually get in Service Catalog forms(Service Portal).
which is Dynamic HTML tables on Catalog forms with Add and Remove rows.
Requirement:
We need to display a table (ex: multi row variable set ) on a catalog form and when user fills a variable (select item) and provides its quantity we need to calculate the price and update the total value as show in below screenshot.
For the above scenario we can
Possibility 1 (Using Custom widget):
1.For Service Portal we can, Develop custom widget and embed it on the catalog form with all the functionalities that are available with Multi row variable set.
2. For ServiceNow Native UI we need to create a macro to re render all the information provided by the user
3. It will take certain time to develop and we need to handle lot of things. But we will have flexibility in doing multiple things as it is custom built.
Possibility 2 (Using Multi row variable set):
For mentioned use case, Using multi row variable set might not be that fruitful due to below issues
1. It wont support capability of accessing other form variables and we cant display separate row with Total as shown in above screenshot
2. When user delete rows by either clicking Remove All or individual remove row buttons,we cannot track those deletes and update our calculations accordingly.
Refer: ServiceNow Docs
My Approach
I tried to figure out an approach which uses the combination of Multi row variable set and a custom widget to achieve mentioned functionality without complex logic or any DOM manipulations.
Solution:
1. Create a multi row variable set with all the necessary variables, In our case Select Item, quantity and price.
2. Create widget and add it to the catalog item as a variable of type Macro
3. In the client script of the widget, try to watch for the changes in the multi row variable set using angular js component ($scope.$watch) as shown below
$scope.$watch(function(){
/* item_prices - Internal Name of multi row variable set */
return $scope.page.g_form.getValue('item_prices');
},function(val){
// Business Logic
});
4. When there are changes , We can calculate the total price by retrieving the value of entire multi row variable set.
example:
[
{
"quantity":"10",
"select_item":"laptop",
"price":"10000"
},
{
"quantity":"30",
"select_item":"keyboard",
"price":"600"
},
{
"quantity":"2",
"select_item":"mouse",
"price":"20"
}
]
5. We can populate the calculated price in any variable out side multi row variable set
OR
We can bind the value to any html element on the widget.
Refer to end result in below screenshot.
Widget Reference:
Body HTML:
<div>
<div ng-if="c.totalPrice" class="total_class pull-right">
<div class="total_text"> Total: </div>
<div> <span class="badge badge-secondary total_value">{{c.totalPrice }} </span> </div>
</div>
</div>
Client Script:
api.controller=function($scope) {
/* widget controller */
var c = this;
c.totalPrice ='';
$scope.$watch(function(){
return $scope.page.g_form.getValue('item_prices');
},function(val){
c.totalPrice ='';
$scope.page.g_form.setValue('total_price','');
if(val !=''){
var obj = JSON.parse(val);
var tPrice=0;
for(var i in obj)
tPrice =parseInt(tPrice)+parseInt(obj[i].price);
if(tPrice!='' && tPrice>0){
c.totalPrice =tPrice;
$scope.page.g_form.setValue('total_price',tPrice);
}
}
});
};
Attached working demo for reference.
https://www.servicenow.com/community/now-platform-articles/multi-row-variable-set-interaction-with-catalog-form-and/ta-p/2319201