Thursday, December 24, 2015

AngularJS - Broadcasting and Emitting Events

AngularJS Scope provides support to broadcast events and handle them. We may want to wait for an event to execute some other activity, e.g. waiting for particular data to be received from an AJAX request.

AngularJS provides two types of events generation:

  1. Emitting - propagates the event upwards in the scope hierarchy.
  2. Broadcasting - propagates the event downwards in the scope hierarchy.

Emitting:

The $scope contains a function $emit() that is used to propagate an event upwards in the scope hierarchy. First parameter of this function is the name of the event that is being emitted, after first parameter we can pass multiple parameters for different purposes, but typically we want to pass data which should be shared with the event listeners.

Broadcasting:

The $scope contains another function $broadcast() this will be used to propagate the event downwards in the scope hierarchy. Contains the same parameters as with $emit function, first parameter will be the event's name, and in the second parameter we can pass our data which should be shared by event listeners.

Controllers can register for the event by using notification function $on() which will be called when the event occurs.

Let's see this example:

demoApp.controller('Controller1', function ($scope, $rootScope, $timeout) {

    $scope.title = 'Controller1';
    $scope.showEvents = false;

    $scope.sendMessage = function () {

        $scope.$broadcast('Controller1_Event_Broadcast', 'Hi from Controller1');
        
        $scope.showEvents = true;
    };

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

        console.log('I am ' + $scope.title + ', Controller2_Event_Emit received with data: ' + data);

    });
});

demoApp.controller('Controller2', function ($scope) {

    $scope.title = 'Controller2';

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

        console.log('I am ' + $scope.title + ', Controller1_Event_Broadcast received with data: ' + data);

        $scope.$emit('Controller2_Event_Emit', 'Hi from Controller2');
    });
});

And in html, the controllers hierarchy should be setup as, Contrller2 should be nested in inside Contrller1's tag. e.g:

Check browser's console to see event messages

we have two controllers, Controller1 will broadcast an event (Controller1_Event_Broadcast) using $scope.$broadcast() function, with string data ('Hi from Controller1'). And Controller2 has registered this event with $scope.$on(), where second parameter 'data' contains the value what we passed when this event is raised. Inside the receiving handler of Controller1_Event_Broadcast event, Controller2 is emitting its own event(Controller2_Event_Emit) with $scope.$emit() function. This emitted event also have a handler defined in Controller1 to receive notification from Controller2 for this event.

In this example we have seen how a Parent controller can broadcast its events to downwards to its children controllers, and how a child controller can emit its events upwards to its parents in the hierarchy.

Events with $rootScope:

But how if both these controllers as siblings to each other, and we may want to raise a global event that both these controllers should be able to handle, because so far we have seen how to handle events either from parent or either from child controllers. So here comes the role of $rootScope, as we know all controllers can access the $rootScope's contents. So in case of siblings controllers, if we want to raise an event that should be handles by all sibling controllers then we have to broadcast that event on the $rootScope. Look at this example:

$scope.sendMessage2 = function () {
       
        $rootScope.$broadcast('RootScope_Broadcast_Event', 'Hi from Controller1 via $rootScope');        
       
    };

Added another function sendMessage2() in Controller1, when this function is called, its broadcasts RootScope_Broadcast_Event event on $rootScope. And all interested controllers can register for this event using the same $on() function, like:

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

        console.log('I am ' + $scope.title + ', RootScope_Broadcast_Event received with data: ' + data);

    });    

2 comments:

  1. Great article.

    Emitting and broadcasting events is especially useful in building complex user interfaces with Angular directives where it enables decoupling of directives in a publish/subscribe fashion.

    ReplyDelete