Modifying Service Portal Widgets On-The-Fly

 

Recently, a customer asked us to remove their Get Help catalog item from the list of Popular Items in the Service Portal because it's not really an item (it's a record producer) and it's accessed from the home page as well as being in the menu bar so it doesn't really belong under Popular Items.

The challenge was, how could this be done WITHOUT changing/modifying the widget (to avoid skipped upgrade updates)

Previously, I've written about how to manipulate portal widgets without modifying them, but that was on submission. This required modifying the widget on load, dynamically changing its contents on-the-fly without actually altering the core widget itself. The trick is to embed the OOB widget and use angular to inject the change.

As you'll see, the code is simple and yet effective, and could be repurposed for a number of other similar applications. Our custom widget acts as a wrapper around the OOB widget (which in this case is sc-category)

Widget HTML Code

<div>
   <sp-widget widget="data.remoteControlWidget"></sp-widget>
</div>

Widget Server Code

(function() {
        data.remoteControlWidget = $sp.getWidget("sc-category");
})();

Widget Client Controller Code

function($scope) {        

        var c = this;
        //We can get the angular data object of BOTH widgets
        var thisWidgetsData     = $scope.data;
        var theOtherWidgetsData = $scope.widget.data.remoteControlWidget.data;

        //Look at the remote scope.data object for sc category to see if have the item we want to hide/remove?
        theOtherWidgetsData.items.forEach(function(item, location){

               //Is our "Get Help" widget on the page?
               if(item.sys_id=='ea8accaedb0508103ea3cd051496198b'){

                       //Angular's injector invoke will allow us to change the scope within a digest
                       window.angular.element(document.body).injector().invoke(function($compile) {

                               //Now we can modify the other widgets scope and angular will do the rest
                               theOtherWidgetsData.items.splice(location,1);
                       });
               }
        })      
}

In essence, all we're doing is remotely accessing the OOB widget's angular scope and then using angular's injector to update that scope.

Although this might seem overly complex, we can look at the scope of any angular widget by holding down the Control key and right-clicking above the widget. Once we've identified what needs to change (in this case, removing an entry from an array), the rest is quite simple.

Have fun!