Following the principle of “separation of concerns”, it is good practice for your portal or application to be made up of self contained functional components, also known as widgets in Service Portal. However sometimes these widgets need to communicate with one another. Thanks to Angular.js this can be accomplished through the use of $broadcast, $emit, and $on methods.
$broadcast and $emit allow you to raise an event in your widget. The difference between $broadcast and $emit is that the former sends the event downwards from parent to child controllers, while $emit sends an event upwards from the current controller to all of its parent controllers. Both methods are available on $scope and $rootScope. You can subscribe to an event using the “$on” event handler.
In this example we will create two widgets that interact using $broadcast and $on.
Widget #1:
Create two buttons that upon click, will $broadcast an event called “customEvent” and pass an object.
HTML:
1 2 3 4 | <div class="panel panel-default panel-body m-t m-b"> <button class="btn btn-default" ng-click="c.clickButton('Cancel')">Cancel</button> <button class="btn btn-primary" ng-click="c.clickButton('Submit')">Submit</button> </div> |
Client Script:
1 2 3 4 5 6 7 8 9 10 | function($rootScope) { var c = this; c.clickButton = function(action) { var obj= { action: action, something: "anything else" }; $rootScope.$broadcast('customEvent', obj); } } |
Widget #2:
Listen for the “customEvent” event, and when triggered, the callback function will update the text.
HTML:
1 2 3 4 5 6 7 8 | <div class="panel panel-default"> <div class="panel-heading"> <h4 class="panel-title">Results</h4> </div> <div class="panel-body"> {{c.text}} </div> </div> |
Client Script:
1 2 3 4 5 6 7 | function($rootScope) { var c = this; c.text = "Hello"; $rootScope.$on('customEvent', function(event,obj) { c.text = "You clicked "+obj.action; }); } |
The final results should look like this:
Thanks for this and your other posts, Nathan. They’re really helpful for those of us learning to build these widgets.
Thanks Nathan! Much appreciated.
Thanks Nathan!
Thanks Nathan, you’re a star.
By the way, why did you use $rootScope on this instead of just $scope?
Cheers
$scope will not work, because each widget has isolated scope, but rootScope can be accessed from both of them 🙂
Great post – very precise.
Hi Nathan,
I have tried your example to communicate between two widgets but I’m working on something that needs to share data between two widgets on different pages. I hope you can help me on this, https://community.servicenow.com/thread/266674
Thank you!
Any solution for this? I’m also stuck with the same problem.
To communicate between two pages, simply pass the data using URL parameters. If you need to pass lots of data you could look at using an Angular Service
Thanks..this article really helped me on synchronizing related widgets
Thanks Nathan. Very good article.
what is the use of declaring something: “anything else” inside the object.
Is it just a variable like action to access through obj and not used here.
What if i want this sync to happen without clicking any button ? how can we do that.
Hey Nathan,
I am working on a service catalog requirement on the sc_cat_item page. The sc_catalog_item widget that is used on the page is cloned and customized. In addition to the sc_catalog_item widget, there is an embedded macro widget on the sc_cat_item page. This macro widget has a checkbox.
When the sc_cat_item page is rendered, in some situation, the submit (order now) button will be disabled. When that happens, the checkbox in the embedded macro widget should be clicked to enable the submit button. I am thinking that broadcasting from the embedded widget and listening from the sc_catalog_item widget will be the way to go. But, unsure how to accomplish this.
Could you please guide me through this?
Thank you very much.
This is amazing!
very usefull!
how do you access a variable in html code from client controller script
Hi, one of our developers build a page with some widgets using the $rootScope.$broadcast and $rootScope.$on. The page works fine in Firefox but doesn’t do anything in Chrome or Edge. I’m not getting any console errors. Did something change with Chrome to prevent broadcast? Does it need to use just $scope now?
Thanks
Nice explaination