Blogger news

Blogger templates

Sunday, August 31, 2014

$broadcast, $emit and $on services in AngularJS



If you are new to AngularJS I would prefer to go through my introduction blog on AngularJS before read this article. Also before proceed with this article you should have a better understanding about $scope and $rootScope. If you are not aware of that read angular documentation.

Angular $emit, $broadcast and $on service will do exactly same thing as Observer design pattern do. If i put it in other way publish an event and subscribe/unsubscribe to it somewhere elseThe Angular event system is brilliant, it makes things flawless and easy to do. Before go to deep I will give a quick understanding about the difference between three.

  • $scope.$emit will fire an event up the $scope.
  • $scope.$broadcast will fire an eventdown the $scope.
  • $scope.$on is how we listen for these events. 
See the signature of each below



// firing an event upwards

$scope.$emit('eventname', 'data to send');


// firing an event downwards

$scope.$broadcast('eventname', {

    property: 'this is my object'

});


// listen for the event in the relevant $scope

$scope.$on('eventname', function (event, data) {

    console.log(data); //logging data

});

$scope.$broadcast

$scope.$broadcast will fire event downwards of the $scope. Assume we have two controllers, a parent controller and a child controller. If I  $broadcast an even from parent controller it always it always will reach $on service in the child controller. $on is the service which is listening for the events propagating from $broadcast/$emit services. See the example below,

eventModule.controller('ParentController', function ($scope) {

    $scope.ParentData = "Only those who dare to fail greatly can ever achieve greatly";

    $scope.SendMessageToChild = function () {
       
        $scope.$broadcast("sampleEvent", $scope.ParentData);
    }
   
});


eventModule.controller("ChildController", function ($scope) {

    $scope.$on("sampleEvent", function (event, data) {
        $scope.ChildData = "Message from parent controller: " + data;
    });

});

and view (html ) below,

<html ng-app="eventModule">
<head>
    <title></title>
</head>
<body>
    <div ng-controller="ParentController">
        Parent Controller : {{ParentData}}
        <br />
        <input type="button" value="BroadCastEventToChild" ng-click="SendMessageToChild()"/>

        <div ng-controller="ChildController">
            Child Controller : {{ChildData}}
        </div>

    </div>
       

    <script src="Scripts/AngularJS/angular.min.js"></script>
    <script src="Scripts/Module/EventModule.js"></script>
    <script src="Scripts/Controllers/ParentController.js"></script>
    <script src="Scripts/Controllers/ChildController.js"></script>
</body>
</html>  

So as I explained before I have created two controllers, ParentController and ChildController. In ParentController I have a function  SendMessageToChild which will call click event of BroadCastEvent' button. In SendMessageToChild function I am calling $scope.$broadcast function in which first parameter is event name and second is the data to pass to child controller. 

When I click button it will broadcast event and in ChildController $scope.$on function which is always listining to the ParentController events. First parameter of "$on" is the event name which will be same as the propagated event name from ParentController. Second parameter is a callback function and first parameter of callback contains event details and second parameter is data which passed from ParentController. When you click button your output will be as below,


$scope.$emit

$scope.$emit works exactly opposite to $scope.$broadcast, it means $scope.$emits propagates event from child to parent. I am reusing the same example with minor modification to add $scope.$emit . See sample below,

eventModule.controller('ParentController', function ($scope) {

    $scope.$on("sampleEvent", function (event, data) {
        $scope.ParentData = "Message from child controller: " + data;
    });
       
});


eventModule.controller("ChildController", function ($scope) {

    $scope.ChildData = "Yeah I am dare to fail";

    $scope.SendMessageToParent = function () {

        $scope.$emit("sampleEvent", $scope.ChildData);
    }
});

and view,

<html ng-app="eventModule">
<head>
    <title></title>
</head>
<body>
    <div ng-controller="ParentController">
        Parent Controller : {{ParentData}}
        <br />
       

        <div ng-controller="ChildController">
            Child Controller : {{ChildData}}
            <br />
            <input type="button" value="BroadCastEventToParent" ng-click="SendMessageToParent()" />
        </div>

    </div>
       

    <script src="Scripts/AngularJS/angular.min.js"></script>
    <script src="Scripts/Module/EventModule.js"></script>
    <script src="Scripts/Controllers/ParentController.js"></script>
    <script src="Scripts/Controllers/ChildController.js"></script>
</body>
</html>

Now after click button will be as below,




Now everything is self explanatory isn't it?? It works exactly opposite to $broadcast, emits event from child to parent.

There is issue with $scope.$broadcast and $scope.event, it works only with immediate parent child relationship. Then how to we can propagates events in all hierarchy? Well that is where $rootScope comes to picture. $rootScope is the base. In other way  all $scope inherits from $rootScope.
The $rootScope Object has the identical $emit, $broadcast, $on methods, but they work slightly differently to how $scope implements them. As $rootScope has no $parent, using an $emit would be pointless, right? Nope, instead, $rootScope.$emit will fire an event for all $rootScope.$on listeners only. The interesting part is that $rootScope.$broadcast will notify all $rootScope.$on as well as$scope.$on listeners. 

I am leaving that you to do work out on $rootScopes  $emit, $broadcast, $on services as it is exactly same as above examples but $rootScope will fire events in all hierarchy.

No comments:

Post a Comment