How can I send my $scope
object from one controller to another using .$emit
and .$on
methods?
function firstCtrl($scop
You must use $rootScope to send and capture events between controllers in same app. Inject $rootScope dependency to your controllers. Here is a working example.
app.controller('firstCtrl', function($scope, $rootScope) {
function firstCtrl($scope) {
{
$rootScope.$emit('someEvent', [1,2,3]);
}
}
app.controller('secondCtrl', function($scope, $rootScope) {
function secondCtrl($scope)
{
$rootScope.$on('someEvent', function(event, data) { console.log(data); });
}
}
Events linked into $scope object just work in the owner controller. Communication between controllers is done via $rootScope or Services.
Below code shows the two sub-controllers from where the events are dispatched upwards to parent controller (rootScope)
<body ng-app="App">
<div ng-controller="parentCtrl">
<p>City : {{city}} </p>
<p> Address : {{address}} </p>
<div ng-controller="subCtrlOne">
<input type="text" ng-model="city" />
<button ng-click="getCity(city)">City !!!</button>
</div>
<div ng-controller="subCtrlTwo">
<input type="text" ng-model="address" />
<button ng-click="getAddrress(address)">Address !!!</button>
</div>
</div>
</body>
var App = angular.module('App', []);
// parent controller
App.controller('parentCtrl', parentCtrl);
parentCtrl.$inject = ["$scope"];
function parentCtrl($scope) {
$scope.$on('cityBoom', function(events, data) {
$scope.city = data;
});
$scope.$on('addrBoom', function(events, data) {
$scope.address = data;
});
}
// sub controller one
App.controller('subCtrlOne', subCtrlOne);
subCtrlOne.$inject = ['$scope'];
function subCtrlOne($scope) {
$scope.getCity = function(city) {
$scope.$emit('cityBoom', city);
}
}
// sub controller two
App.controller('subCtrlTwo', subCtrlTwo);
subCtrlTwo.$inject = ["$scope"];
function subCtrlTwo($scope) {
$scope.getAddrress = function(addr) {
$scope.$emit('addrBoom', addr);
}
}
http://jsfiddle.net/shushanthp/zp6v0rut/
To send $scope object
from one controller to another, I will discuss about $rootScope.$broadcast
and $rootScope.$emit
here as they are used most.
Case 1:
$rootScope.$broadcast:-
$rootScope.$broadcast('myEvent',$scope.data);//Here `myEvent` is event name
$rootScope.$on('myEvent', function(event, data) {} //listener on `myEvent` event
$rootScope
listener are not destroyed automatically. You need to destroy it using $destroy
. It is better to use $scope.$on
as listeners on $scope
are destroyed automatically i.e. as soon as $scope is destroyed.
$scope.$on('myEvent', function(event, data) {}
Or,
var customeEventListener = $rootScope.$on('myEvent', function(event, data) {
}
$scope.$on('$destroy', function() {
customeEventListener();
});
Case 2:
$rootScope.$emit:
$rootScope.$emit('myEvent',$scope.data);
$rootScope.$on('myEvent', function(event, data) {}//$scope.$on not works
The major difference in $emit and $broadcast is that $rootScope.$emit event must be listened using $rootScope.$on, because the emitted event never comes down through the scope tree..
In this case also you must destroy the listener as in the case of $broadcast.
Edit:
I prefer not to use
$rootScope.$broadcast + $scope.$on
but use$rootScope.$emit+ $rootScope.$on
. The$rootScope.$broadcast + $scope.$on
combo can cause serious performance problems. That is because the event will bubble down through all scopes.
Edit 2:
The issue addressed in this answer have been resolved in angular.js version 1.2.7. $broadcast now avoids bubbling over unregistered scopes and runs just as fast as $emit.
First of all, parent-child scope relation does matter. You have two possibilities to emit some event:
$broadcast
-- dispatches the event downwards to all child scopes,$emit
-- dispatches the event upwards through the scope hierarchy.I don't know anything about your controllers (scopes) relation, but there are several options:
If scope of firstCtrl
is parent of the secondCtrl
scope, your code should
work by replacing $emit
by $broadcast
in firstCtrl
:
function firstCtrl($scope)
{
$scope.$broadcast('someEvent', [1,2,3]);
}
function secondCtrl($scope)
{
$scope.$on('someEvent', function(event, mass) { console.log(mass); });
}
In case there is no parent-child relation between your scopes you
can inject $rootScope
into the controller and broadcast the event
to all child scopes (i.e. also secondCtrl
).
function firstCtrl($rootScope)
{
$rootScope.$broadcast('someEvent', [1,2,3]);
}
Finally, when you need to dispatch the event from child controller
to scopes upwards you can use $scope.$emit
. If scope of firstCtrl
is parent of the secondCtrl
scope:
function firstCtrl($scope)
{
$scope.$on('someEvent', function(event, data) { console.log(data); });
}
function secondCtrl($scope)
{
$scope.$emit('someEvent', [1,2,3]);
}
<!DOCTYPE html>
<html>
<head>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
var app = angular.module('MyApp',[]);
app.controller('parentCtrl',function($scope){
$scope.$on('MyEvent',function(event,data){
$scope.myData = data;
});
});
app.controller('childCtrl',function($scope){
$scope.fireEvent = function(){
$scope.$emit('MyEvent','Any Data');
}
});
</script>
</head>
<body ng-app="MyApp">
<div ng-controller="parentCtrl" ng-model="myName">
{{myData}}
<div ng-controller="childCtrl">
<button ng-click="fireEvent()">Fire Event</button>
</div>
</div>
</body>
</html>
I would additionally suggest a 4th option as a better alternative to the proposed options by @zbynour.
Use $rootScope.$emit
rather than $rootScope.$broadcast
regardless of the relationship between trasmitting and receiving controller. That way, the event remains within the set of $rootScope.$$listeners
whereas with $rootScope.$broadcast
the event propagates to all children scopes, most of which will probably not be listeners of that event anyway. And of course in the receiving controller's end you just use $rootScope.$on
.
For this option you must remember to destroy the controller's rootScope listeners:
var unbindEventHandler = $rootScope.$on('myEvent', myHandler);
$scope.$on('$destroy', function () {
unbindEventHandler();
});