Applies to Quebec and Rome releases.
Yesterday I learned something surprising about Service Portal Widgets. Maybe other developer already know this but it was a surprise to me. Even after I have worked with the new Service Portal since it was released. The problem first appeared after upgrading my PDI to Paris and Rome.
I am building a service portal application with multiple widgets that communicate via angular service. So when a button is clicked in one widget a message is sent and the other widgets acts accordingly for example by showing or hiding information etc.
I started this on a Paris PDI before Quebec was released and everything was fine. Then because of other work I did not continue working on this until after my PDI was upgraded to Rome. Then the problem appeared. Now one (out of 10) widgets suddenly reacted very slowly on messages. The html would not update immediately, it could take up to about one minute.
I spent many hours debugging, commenting code out etc to try to isolate what was causing this. Then finally I found the answer in a stackoverflow question that mentioned $scope.$apply(). I had never heard about this and never seen it used in a OOB widget. It is used in about 10 widgets.
The AngularJS documentation says
$apply() is used to execute an expression in AngularJS from outside of the AngularJS framework.
So of course I immediately tried to add this simple line of code and voila the widget in question updated fast again. A simple solution that took many hours for me to discover.
Consider following code in the client controller part of a widget. This code subscribes to a service and wait for a specific message. When that message arrives it updates a variable in $scope that is displayed in the html with the {{}} binding syntax.
$(document).ready(function () {
var removeListener = someService.addListener(function (action) {
if (action.action == 'doSomething') {
$scope.field = action.someData;
$scope.$apply();
}
});
});
Without the $scope.$apply() the update of html can take as long as one minute when running on Quebec or later releases. With the line it is updated immediately.
I have confirmed that Quebec introduced changes to the Service Portal that makes this necessary. I confirmed by loading my application on a Paris PDI and ran the widget without the $apply() and it worked as expected with no delays. Then I upgraded the PDI to Quebec and made no changes to the widget but now it was extremely slow. Then I added the $apply() and the widget worked fast again. To re-confirm I upgraded the PDI to Rome and the same would happen.
So the question is when to use $apply. Well the documentation says whenever you update $scope outside a digest. A simple way to find out is just to add it whenever you make updates to $scope. If it is not necessary then you will get an error message in the console.log stating that code is already running in digist so $apply() is not required.
As I mentioned this code is not widely used in OOB Widgets which is why I never ran into this. I usually go check out new widgets when a new release is available to learn about new stuff in the portal.