Interact with service portal widget in catalog item

larstange
Mega Sage

Hi all

So we are currently analyzing if we can replace our current service catalog (based on the standard ServiceNow interface and self-service module - no CMS) with the Service Portal.

We have a number of more advanced catalog items, where we use UI macro to display additional information to the user, that we are not able to achieve using the available variable types.

As UI Macros are not available in Service Portal we need a replacement. Here I have discovered a new "widget" field the catalog varaible form, where you can point to a portal widget and get it displayed on the catalog item.

But we need to be able to interact with the widget and affect what it is displaying based on the values selected in the variables on the catalog item.
Basically I want to write to the data in the widget's scope via a catalog client script.

The normal way of accessing an angular scope from the outside is using the syntax

var scope = angular.element($("#[element]")).scope();

So I have created a clone of the Hello World 1 widget and modified it so the input field has an ID

<div>

Enter your name:

<input id="helloWorld" type="text" ng-model="c.data.sometext" ng-change="c.display()"/>

<h1>{{ c.data.message }}</h1>

</div>

Then I try to access the scope from an onChange script in the catalog item

    var scope = angular.element(document.getElementById('helloWorld')).scope();

      scope.$apply(function(){

              scope.data.sometext = newValue;

      });

But i get an error in the console saying (g_env) [SCRIPT:EXEC] Error while running Client Script "onChange_name": TypeError: Cannot read property 'element' of null

So it looks like the catalog client scripts does not have access to the loaded angular in any way. I have tried some different thinks to try and be able to access angular but no avail.

If anybody has an idea I would appreciate any pointers - if we don't solve this, then the portal is not an option.

Regards

Lars

nathanfirth

1 ACCEPTED SOLUTION

larstange
Mega Sage

I found the solution my self.



You can read and write to the catalog variables using $scope.page.g_form. and then any of the g_form function like setValue and getValue.


Then I use the angular $watch feature to define a function to watch for changes in the catalog variable and then update my data in the widget scope.



It looks like this



HTML template


  <div>


  Data from catalog variable:


  <h1>{{ c.data.message }}</h1>


  </div>


Client Script Controller



function($scope) {


        var c = this;



        //Watch for changes in the name variable


        $scope.$watch(function () {


                  return $scope.page.g_form.getValue('name');


        }, function (value) {


        //Update local data object with data from variable


        c.data.message = value ? 'Content of name variable: ' + value : '';


});


}




Result - the text in the widget is updated when you change focus away from the catalog variable


find_real_file.png


View solution in original post

26 REPLIES 26

larstange
Mega Sage

Hi Milap



The widget will only be visible if you open the catalog item through the Service Portal


Daniel Pettet
ServiceNow Employee
ServiceNow Employee

I would be careful with using $scope.$watch as you are hoping that angular can pick up on all the custom logic ServiceNow has for it's elements. Eg, reference fields won't work with this solution as they are complex HTML components.



A better solution would be to use standard catalog scripts and fire standard JS events like CustomEvent.fire('my.namespaced.event') and then your widgets listen via CustomEvent.observe('my.namespaced.event', <function callback>).


Hi Daniel



Thanks for the tip - I can see some clear advantages by doing it that way - I will surely experiment with that method as well!



That said, it do seem to work quite well with a multi line string variable and just let the widget watch for changes.


But in the case where you need more than one widget pr catalog item I believe that your method will be better


Reference fields do work, as it returns the sys_id of the referenced record.


This was exactly what I needed..!
OnChange Catalog Client Script on the record producers sends "newValue" to the Client Script of the Widget. 
Now I can modify the widget appearance (showing a button) if a certain value is chosen in the field of the record producer 🙂

 

Thanks!