Getting displayed variables in service portal

robertyoung
Giga Contributor

We have long had a custom client script as part of a variable set that inspected the attributes of all of the options contained in: g_form.nameMap.

On submit this allowed us to construct a list of all of the field names that were visible at the time of submission. This list is important later in our business processes where we use it to decide which fields to send to one of our vendors over a web service call.

We've been using service portal for a while now and are currently in the process of moving all of our catalog items over. I need to re-create this "get visible variables" capability in portal but I can't figure out how the variables in portal relate to their counterparts attached to the catalog item. There is a GUID associated with the input on portal but it doesn't seem to match anything else I can think of.

I'm looking for anyone who has done anything similar or who has knowledge of how the variables are named (id) in portal to help me chip away at this.

1 ACCEPTED SOLUTION

ChrisBurks
Mega Sage

Hi Robert,



From the Service Portal side you could possibly embed a Service Portal widget into the catalog item and do something like this to capture all the necessary variables and their values:



Widget Client Controller Script:



function($scope, $rootScope) {


      /* widget controller */


      var c = this;


      $rootScope.$on('field.change', function(){


              c.variables = $scope.page.g_form.getFieldNames().filter(function(field){


                      return $scope.page.g_form.isVisible(field);


              }).map(function(field){


                      var obj = {};


                      obj.name = $scope.page.g_form.getLabel(field);


                      obj.value = $scope.page.g_form.getValue(field);


                      obj.display_value = $scope.page.g_form.getDisplayValue(field);


                      obj.isVisible = $scope.page.g_form.isVisible(field);


                      return obj;


              });


              console.log("Changed", c.variables)


      })


}



That script will search through and gather all the visible variables in the catalog item it's associate with when a field value changes. (input fields will trigger on blur and select fields will change after a selection). And then it's just console logging out the result. But you can have it do what's needed.


However, it will only get the values of the native side variables. If you have Service Portal side variables you can directly access them from the scope. If you have UI Macro variables using a UI macro or UI page of the sort then those would have to be handled on native side or duplicated Service Portal side.



Edit:



Thinking about this though I forgot to ask, Is it not working in the Service Portal or is the issue that you've added variables on the Service Portal side?



If it simply isn't working below are a couple of questions:


      What errors are you getting? (You might need to use "inspect element" to see the errors.


      Did you set the Client Script to run in both Desktop and Mobile? (Service Portal is considered mobile)


View solution in original post

8 REPLIES 8

Thanks, I went ahead and marked your actual answer as correct. There doesn't seem to be a very good way of mapping the variables back to their actual variable definition which is a bummer. No way to get the actual variable's name or sys_id as far as i can tell from the documentation. I guess we'll just have to use the label and come up with a plan when a service has 2 variables called the same thing.


Hmmm.... maybe I don't fully understand the requirements. But you can grab both the sys_id and field name of the variables in Service Portal.


With a little modification and the help of the Server Script a field mapping or the variable field name (i.e. short_description) along with its sys_id can be achieved.



Server Script:



if(input){


      var io = new GlideRecord('item_option_new');


      io.get(input.sys_id);


      data.realFieldName = io.getValue('name');


}




Client Controller:


$rootScope.$on('field.change', function(){


              c.variables = $scope.page.g_form.getFieldNames().filter(function(field){


                      return $scope.page.g_form.isVisible(field);


              }).map(function(field){


                      var sys_id = field.replace("IO:", "");


                      c.server.get({sys_id: sys_id}).then(function(resp){


                              c.obj = {};


                              c.obj.fieldName = resp.data.realFieldName;


                              c.obj.sys_id = sys_id;


                              c.obj.name = $scope.page.g_form.getLabel(field);


                              c.obj.value = $scope.page.g_form.getValue(field);


                              c.obj.display_value = $scope.page.g_form.getDisplayValue(field);


                            c.obj.isVisible = $scope.page.g_form.isVisible(field);


                      });


                      return c.obj;


              });


              console.log("Changed", c.variables)


      })



And if you don't need the value but just the mapping you probably don't need to listen for a change. And you could remove the calls for getting the values.



If you need to capture all of this back on the native side then just have a hidden variable to stuff it in by using $scope.page.g_form.setValue() method.





I hope that helps.


I didn't realize that the GUID on the field was the sys_id from item option new. I thought for sure I had ruled that out days ago. Thanks for that! Just knowing that I could probably have rigged something up.



is the "field" that is getting passed in through each function the object that comes back when the field.change event fires? I understand enough about this now to implement but I don't fully grasp where that value comes from. It's clearly the field we care about during this iteration but where is the loop?



I'm going to be looking at this for a while to understand all of it. Thanks so much again for the time.


My fault. I should have include some commenting. All the looping is performed with a couple of array methods, .filter and .map.


They both take callbacks and return arrays and allow for chaining.


Here are the scripts with comments.



Server Script:



if(input){


      var io = new GlideRecord('item_option_new');


      // use the input object from the client side


      // access the sys_id property we set client side


      // fetch the item_option_new record according to the passed sys_id


      io.get(input.sys_id);


     


      // return the actual field name of the variable


      data.realFieldName = io.getValue('name');


}




Client controller Script:


// listens for a broadcast/emit event of a field changing. Note: input fields trigger on blur


      $rootScope.$on('field.change', function(){


         


          // getFieldNames() brings back an array of strings of the field sys_ids correlating to the


          // id of the element of the variable: ["IO:xxxxx...", "IO:xxxx...",...]


          c.variables = $scope.page.g_form.getFieldNames().filter(function(field){


                // since it's an array we can use the .filter method


                // passing each id as "field" and checking if it's visible


                // only visible variables will be returned which should give


                // a new array


                return $scope.page.g_form.isVisible(field);


               


          }).map(function(field){


                // since the return is still an array use the .map method


                // each item passed again as "field"


                // here the script is stripping the "IO:" from the string to get


                // the real sys_id


                var sys_id = field.replace("IO:", "");


               


                // once we have the real sys_id we use server.get to pass the input


                // object to the server side to do some processing


                // it returns a promise


                // the server side script is fetching the variable field name


                // and returns it in the data object property realFieldName we


                // defined in the server script


                c.server.get({sys_id: sys_id}).then(function(resp){


                     


                      // create our own object to create a mapping


                      c.obj = {};


                      c.obj.fieldName = resp.data.realFieldName;


                      c.obj.sys_id = sys_id;


                      c.obj.name = $scope.page.g_form.getLabel(field);


                      c.obj.value = $scope.page.g_form.getValue(field);


                      c.obj.display_value = $scope.page.g_form.getDisplayValue(field);


                      c.obj.isVisible = $scope.page.g_form.isVisible(field);


                })


               


                // return our object


                // .map will always return the same length of items in the given array


                return c.obj;


          });


          console.log("Changed", c.variables)


      })




Another way to write the client controller:


        $rootScope.$on('field.change', function(){


          c.variables = $scope.page.g_form.getFieldNames()


                                        .filter(getVisibleItems)


                                        .map(getFieldNames);


        });



      function getVisibleItems(field){


          return $scope.page.g_form.isVisible(field);


    }


   


      function getFieldNames(field){


          var sys_id = field.replace("IO:", "");


          c.server.get({sys_id: sys_id}).then(function(resp){


                c.obj = {};


                c.obj.fieldName = resp.data.realFieldName;


                c.obj.sys_id = sys_id;


                c.obj.name = $scope.page.g_form.getLabel(field);


                c.obj.value = $scope.page.g_form.getValue(field);


                c.obj.display_value = $scope.page.g_form.getDisplayValue(field);


                c.obj.isVisible = $scope.page.g_form.isVisible(field);


            }


              return c.obj;


      }