Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

$on and $broadcast in angular

People also ask

What is $emit $broadcast and $on in AngularJS?

The difference between $broadcast() and $emit() is that the former sends the event from the current controller to all of its child controllers. That means $broadcast() sends an even downwards from parent to child controllers. The $emit() method, on the other hand, does exactly opposite.

What is $on in AngularJS?

$. on is just a function that attaches an event listener. Read the docs. In my experience with AngularJS, which is admittedly limited, $on works nearly as same as the jQuery on function.

What is broadcasting in angular?

Broadcast messaging means that a sender, the Publisher, sends messages to several receivers, the Subscribers. Any component can via the Publisher send messages to any other component subscribing to the Publisher Service.

What is $emit in AngularJS?

$emit() Function. The AngularJS $emit method is used to dispatches an event name upwards and travel up to $rootScope. scope listeners. The $emit propagatesevent name upward and travel upwards toward $rootScope. scope listeners and calls all registered listeners along the way.


If you want to $broadcast use the $rootScope:

$scope.startScanner = function() {

    $rootScope.$broadcast('scanner-started');
}

And then to receive, use the $scope of your controller:

$scope.$on('scanner-started', function(event, args) {

    // do what you want to do
});

If you want you can pass arguments when you $broadcast:

$rootScope.$broadcast('scanner-started', { any: {} });

And then receive them:

$scope.$on('scanner-started', function(event, args) {

    var anyThing = args.any;
    // do what you want to do
});

Documentation for this inside the Scope docs.


First, a short description of $on(), $broadcast() and $emit():

  • .$on(name, listener) - Listens for a specific event by a given name
  • .$broadcast(name, args) - Broadcast an event down through the $scope of all children
  • .$emit(name, args) - Emit an event up the $scope hierarchy to all parents, including the $rootScope

Based on the following HTML (see full example here):

<div ng-controller="Controller1">
    <button ng-click="broadcast()">Broadcast 1</button>
    <button ng-click="emit()">Emit 1</button>
</div>

<div ng-controller="Controller2">
    <button ng-click="broadcast()">Broadcast 2</button>
    <button ng-click="emit()">Emit 2</button>
    <div ng-controller="Controller3">
        <button ng-click="broadcast()">Broadcast 3</button>
        <button ng-click="emit()">Emit 3</button>
        <br>
        <button ng-click="broadcastRoot()">Broadcast Root</button>
        <button ng-click="emitRoot()">Emit Root</button>
    </div>
</div>

The fired events will traverse the $scopes as follows:

  • Broadcast 1 - Will only be seen by Controller 1 $scope
  • Emit 1 - Will be seen by Controller 1 $scope then $rootScope
  • Broadcast 2 - Will be seen by Controller 2 $scope then Controller 3 $scope
  • Emit 2 - Will be seen by Controller 2 $scope then $rootScope
  • Broadcast 3 - Will only be seen by Controller 3 $scope
  • Emit 3 - Will be seen by Controller 3 $scope, Controller 2 $scope then $rootScope
  • Broadcast Root - Will be seen by $rootScope and $scope of all the Controllers (1, 2 then 3)
  • Emit Root - Will only be seen by $rootScope

JavaScript to trigger events (again, you can see a working example here):

app.controller('Controller1', ['$scope', '$rootScope', function($scope, $rootScope){
    $scope.broadcastAndEmit = function(){
        // This will be seen by Controller 1 $scope and all children $scopes 
        $scope.$broadcast('eventX', {data: '$scope.broadcast'});

        // Because this event is fired as an emit (goes up) on the $rootScope,
        // only the $rootScope will see it
        $rootScope.$emit('eventX', {data: '$rootScope.emit'});
    };
    $scope.emit = function(){
        // Controller 1 $scope, and all parent $scopes (including $rootScope) 
        // will see this event
        $scope.$emit('eventX', {data: '$scope.emit'});
    };

    $scope.$on('eventX', function(ev, args){
        console.log('eventX found on Controller1 $scope');
    });
    $rootScope.$on('eventX', function(ev, args){
        console.log('eventX found on $rootScope');
    });
}]);

One thing you should know is $ prefix refers to an Angular Method, $$ prefixes refers to angular methods that you should avoid using.

below is an example template and its controllers, we'll explore how $broadcast/$on can help us achieve what we want.

<div ng-controller="FirstCtrl">
    <input ng-model="name"/> 
    <button ng-click="register()">Register </button>
</div>

<div ng-controller="SecondCtrl">
    Registered Name: <input ng-model="name"/> 
</div>

The controllers are

app.controller('FirstCtrl', function($scope){
    $scope.register = function(){

    }
});

app.controller('SecondCtrl', function($scope){

});

My question to you is how do you pass the name to the second controller when a user clicks register? You may come up with multiple solutions but the one we're going to use is using $broadcast and $on.

$broadcast vs $emit

Which should we use? $broadcast will channel down to all the children dom elements and $emit will channel the opposite direction to all the ancestor dom elements.

The best way to avoid deciding between $emit or $broadcast is to channel from the $rootScope and use $broadcast to all its children. Which makes our case much easier since our dom elements are siblings.

Adding $rootScope and lets $broadcast

app.controller('FirstCtrl', function($rootScope, $scope){
    $scope.register = function(){
        $rootScope.$broadcast('BOOM!', $scope.name)
    }
});

Note we added $rootScope and now we're using $broadcast(broadcastName, arguments). For broadcastName, we want to give it a unique name so we can catch that name in our secondCtrl. I've chosen BOOM! just for fun. The second arguments 'arguments' allows us to pass values to the listeners.

Receiving our broadcast

In our second controller, we need to set up code to listen to our broadcast

app.controller('SecondCtrl', function($scope){
  $scope.$on('BOOM!', function(events, args){
    console.log(args);
    $scope.name = args; //now we've registered!
  })
});

It's really that simple. Live Example

Other ways to achieve similar results

Try to avoid using this suite of methods as it is neither efficient nor easy to maintain but it's a simple way to fix issues you might have.

You can usually do the same thing by using a service or by simplifying your controllers. We won't discuss this in detail but I thought I'd just mention it for completeness.

Lastly, keep in mind a really useful broadcast to listen to is '$destroy' again you can see the $ means it's a method or object created by the vendor codes. Anyways $destroy is broadcasted when a controller gets destroyed, you may want to listen to this to know when your controller is removed.


//Your broadcast in service

(function () { 
    angular.module('appModule').factory('AppService', function ($rootScope, $timeout) {

    function refreshData() {  
        $timeout(function() {         
            $rootScope.$broadcast('refreshData');
        }, 0, true);      
    }

    return {           
        RefreshData: refreshData
    };
}); }());

//Controller Implementation
 (function () {
    angular.module('appModule').controller('AppController', function ($rootScope, $scope, $timeout, AppService) {            

       //Removes Listeners before adding them 
       //This line will solve the problem for multiple broadcast call                             
       $scope.$$listeners['refreshData'] = [];

       $scope.$on('refreshData', function() {                                                    
          $scope.showData();             
       });

       $scope.onSaveDataComplete = function() { 
         AppService.RefreshData();
       };
    }); }());