Cross controller communication with $emit and $on
AngularJS applications may need to communicate across the controllers. Such communication might be needed to send notifications or to pass data between the controllers. Although there can be different approaches to achieving this goal, one that is readily available is that of using $scope and $rootScope objects. Both of these objects - $scope and $rootScope - support three methods, namely - $broadcast(), $emit(), and $on() - that facilitate an event-driven publisher-subscriber model for sending notifications and passing data between the controllers. This article discusses how to raise events using $emit() and then how to handle those events using $on() method.
How $emit() and $on() work:
Before you dig into the examples discussed below, it would be worthwhile to take a quick look at the purpose and use of $emit() and $on() methods.
$emit() allows you to raise an event in your AngularJS application. It sends an event upwards from the current controller to all of its parent controllers. From the syntax point-of-view, a typical call to $emit() will look like this:
$scope.$emit("MyEvent",date);
Here, MyEvent is a user-defined name of the event that you wish to raise. The optional data parameter can be any type of data you wish to pass when MyEvent is dispatched by the system. For example, if you wish to pass data from one controller to another, that data can go as this second parameter.
The event raised by $emit() can be handled by wiring an event handler using the $on() method. A typical call to $on() method will look like this:
$scope.$on("MyEvent",function(evt,data){ //handler code here });
Now that you know what $emit() and $on() methods do, let's put them to use in the following examples:
Event system on $scope and $rootScope, When it comes to communicating between two or more AngularJS controllers, there can be two possible arrangements:
- The controllers under consideration are nested, controllers. This means that they have a parent-child relationship.
- The controllers under consideration are sibling controllers. This means that they are at the same level without any parent-child relationship.
To see how $emit() and $on() can be used with nested controllers, let us develop a simple application as shown below:
The above application consists of six AngularJS controllers - VehicleCtrl, CarCtrl, BusCtrl, BRTBusCtrl, TrainCtrl, and LocalCtrl. Here, VehicleCtrl, BusCtrl, and BRTBusCtrl are nested controllers inside each other. TrainCtrl and LocalCtrl are nested controller inside each other. (VehicleCtrl , TrainCtrl) and (CarCtrl, BusCtrl) are siblings.
The HTML markup of the page will look like this:
<div ng-app="TransportApp"> <div ng-controller="VehicleCtrl"> <div ng-controller="CarCtrl"></div> <div ng-controller="BusCtrl"> <div ng-controller="BRTBusCtrl"></div> </div> </div> <div ng-controller="TrainCtrl"> <div ng-controller="LocalCtrl"></div> </div> </div>
Now all controllers register to TransportApp. Vehicle controller has two children controller as Car controller and Bus controller The Bus controller has a child controller named as BRTBus controller. BRTBusCtrl controller raises an event named as message with help of $emit() method. Events send an object ({ "message": "BRT Bus Controller Emit"} ) when the corresponding event is dispatched. You can easily substitute a string data instead of object. All controllers handle the event message and print an object in console by $on.
angular.module("TransportApp", []) .controller("VehicleCtrl", function ($scope) { $scope.$on("message", function(event, object) { console.log("Controller : VehicleCtrl Recieved Message : " + object.message); }); }) .controller("CarCtrl", function ($scope) { $scope.$on("message", function(event, object) { console.log("Controller : CarCtrl Recieved Message : " + object.message); }); }) .controller("BusCtrl", function ($scope) { $scope.$on("message", function(event, object) { console.log("Controller : BusCtrl Recieved Message : " + object.message); }); }) .controller("BRTBusCtrl", function ($scope, $rootScope) { $scope.$on("message", function(event, object) { console.log("Controller : BRTBusCtrl Recieved Message : " + object.message);\ }); $scope.$emit("message",{ "message": "BRT Bus Controller Emit" }); }) .dcontroller("TrainCtrl", function ($scope) { $scope.$on("message", function(event, object) { console.log("Controller : TrainCtrl Recieved Message : " + object.message); }); }) .controller("LocalCtrl", function ($scope) { $scope.$on("message", function(event, object) { console.log("Controller : LocalCtrl Recieved Message : " + object.message); }); })
Now let's see the code of all the controllers mentioned above in action.
All controllers handle the event message. Guess, what the result would be? When we execute this example, only three controllers handle this event, namely- BRTBusCtrl, BusCtrl, Vehicle controller. Why? This is because the event is raised by the $emit() method, and that event should be handled by its parent controllers as well as the controller itself. So other controllers cannot handle the event message.
Let’s look at the output, shall we?
Controller : BRTBusCtrlRecieved Message : BRT Bus Controller Emit Controller : BusCtrlRecieved Message : BRT Bus Controller Emit Controller : VehicleCtrlRecieved Message : BRT Bus Controller Emit
As shown in the above output, the “BRT bus controller” string is printed onto the console, which was invoked by the $emit() method by the BRTBusCtrl controller.
Wounding up, $emit() method raises an event and communicates across controllers. This communication should be on a parent-child chain. If we need to share that event only with specific arrow controllers, which are the parents of the invoking controller, then $emit() plays a very important role.
There are other methods also which can be used to communicate between controllers. However, this approach is simpler and easier to understand as it is more straightforward. To know more examples, check out the link below:
click on https://github.com/Tathe/Angular-JS-Blog/blob/master/README.md