Events
Parameters#
Parameters | Values types |
---|---|
event | Object {name: “eventName”, targetScope: Scope, defaultPrevented: false, currentScope: ChildScope} |
args | data that has been passed along with event execution |
Using angular event system
$scope.$emit
Using $scope.$emit
will fire an event name upwards through the scope hierarchy and notify to the $scope
.The event life cycle starts at the scope on which $emit
was called.
Working wireframe :
$scope.$broadcast
Using $scope.$broadcast
will fire an event down the $scope
. We can listen of these events using $scope.$on
Working wireframe :
Syntax :
// firing an event upwards
$scope.$emit('myCustomEvent', 'Data to send');
// firing an event downwards
$scope.$broadcast('myCustomEvent', {
someProp: 'some value'
});
// listen for the event in the relevant $scope
$scope.$on('myCustomEvent', function (event, data) {
console.log(data); // 'Data from the event'
});
Instead of $scope
you can use $rootScope
, in that case your event will be available in all the controllers regardless of that controllers scope
Clean registered event in AngularJS
The reason to clean the registered events because even the controller has been destroyed the handling of registered event are still alive. So the code will run as unexpected for sure.
// firing an event upwards
$rootScope.$emit('myEvent', 'Data to send');
// listening an event
var listenerEventHandler = $rootScope.$on('myEvent', function(){
//handle code
});
$scope.$on('$destroy', function() {
listenerEventHandler();
});
Uses and significance
These events can be used to communicate between 2 or more controllers.
$emit
dispatches an event upwards through the scope hierarchy, while $broadcast
dispatches an event downwards to all child scopes.This has been beautifully explained here.
There can be basically two types of scenario while communicating among controllers:
- When controllers have Parent-Child relationship. (we can mostly use
$scope
in such scenarios)
- When controllers are not independent to each other and are needed to be informed about each others activity. (we can use
$rootScope
in such scenarios)
eg: For any ecommerce website, suppose we have ProductListController
(which controls the product listing page when any product brand is clicked ) and CartController
(to manage cart items) . Now, when we click on Add to Cart button , it has to be informed to CartController
as well, so that it can reflect new cart item count/details in the navigation bar of the website. This can be achieved using $rootScope
.
With $scope.$emit
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
<script>
var app = angular.module('app', []);
app.controller("FirstController", function ($scope) {
$scope.$on('eventName', function (event, args) {
$scope.message = args.message;
});
});
app.controller("SecondController", function ($scope) {
$scope.handleClick = function (msg) {
$scope.$emit('eventName', {message: msg});
};
});
</script>
</head>
<body ng-app="app">
<div ng-controller="FirstController" style="border:2px ;padding:5px;">
<h1>Parent Controller</h1>
<p>Emit Message : {{message}}</p>
<br />
<div ng-controller="SecondController" style="border:2px;padding:5px;">
<h1>Child Controller</h1>
<input ng-model="msg">
<button ng-click="handleClick(msg);">Emit</button>
</div>
</div>
</body>
</html>
With $scope.$broadcast
:
<html>
<head>
<title>Broadcasting</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.js"></script>
<script>
var app = angular.module('app', []);
app.controller("FirstController", function ($scope) {
$scope.handleClick = function (msg) {
$scope.$broadcast('eventName', {message: msg});
};
});
app.controller("SecondController", function ($scope) {
$scope.$on('eventName', function (event, args) {
$scope.message = args.message;
});
});
</script>
</head>
<body ng-app="app">
<div ng-controller="FirstController" style="border:2px solid ; padding:5px;">
<h1>Parent Controller</h1>
<input ng-model="msg">
<button ng-click="handleClick(msg);">Broadcast</button>
<br /><br />
<div ng-controller="SecondController" style="border:2px solid ;padding:5px;">
<h1>Child Controller</h1>
<p>Broadcast Message : {{message}}</p>
</div>
</div>
</body>
</html>
Always deregister $rootScope.$on listeners on the scope $destory event
$rootScope.$on listeners will remain in memory if you navigate to another controller. This will create a memory leak if the controller falls out of scope.
Don’t
angular.module('app').controller('badExampleController', badExample);
badExample.$inject = ['$scope', '$rootScope'];
function badExample($scope, $rootScope) {
$rootScope.$on('post:created', function postCreated(event, data) {});
}
Do
angular.module('app').controller('goodExampleController', goodExample);
goodExample.$inject = ['$scope', '$rootScope'];
function goodExample($scope, $rootScope) {
var deregister = $rootScope.$on('post:created', function postCreated(event, data) {});
$scope.$on('$destroy', function destroyScope() {
deregister();
});
}