In this blog post we will see in more detail about angular $scope variable
We use $scope to bind data between angular and DOM. $scope is injected to a controller using Dependency Injection.
$scope is local to each controller, i.e it is not shared between controllers.
$rootScope
$rootScope is the top level scope object and all other scopes created are child to this scope. These is only a single $rootScope in a single angular application. Lets see a working example of $rootScope and how its shared between 2 controllers.
var mainMod = angular.module('MainApp', []);
mainMod.controller('MainCtrl', ['$scope','$rootScope',
function ($scope,$rootScope) {
$scope.update = function(){
$rootScope.text2 = $scope.text1;
}
}
]);
mainMod.controller('MainCtrl2', ['$scope','$rootScope',
function ($scope,$rootScope) {
$scope.update = function(){
$rootScope.text1 = $scope.text2;
}
}
]);
Our HTML code
<body ng-app='MainApp'>
<div ng-controller='MainCtrl'>
<div>
<div>Controller1</div>
<input type='text' ng-model='text1'/>
<button type='button' ng-click='update();'>Update</button>
</div>
</div>
<div ng-controller='MainCtrl2′>
<div>
<div>Controller2</div>
<input type='text' ng-model='text2'/>
<button type='button' ng-click='update();'>Update</button>
</div>
</div>
</body>
In the above example, if type text in first controller and press ‘Update’ button it gets reflected to the second controller as well. Using this we see that $rootScope is common and shared between all controllers.
More details here
$watch
$scope and $rootScope provide a $watch function. $watch function is used to listen for any changes in $scope variables. More details here Lets extend the above example and see its working
var mainMod = angular.module('MainApp', []);
mainMod.controller('MainCtrl', ['$scope','$rootScope',
function ($scope,$rootScope) {
$scope.$watch('text1',function(newValue,oldValue){
if(newValue){
$rootScope.text2 = newValue;
}
});
}
]);
mainMod.controller('MainCtrl2', ['$scope','$rootScope',
function ($scope,$rootScope) {
$scope.$watch('text2′,function(value){
if(value){
$rootScope.text1 = value;
}
});
}
]);
<body ng-app='MainApp'>
<div ng-controller='MainCtrl'>
<div>
<div>Controller1</div>
<input type='text' ng-model='text1'/>
</div>
</div>
<div ng-controller='MainCtrl2′>
<div>
<div>Controller2</div>
<input type='text' ng-model='text2'/>
</div>
</div>
</body>
Now if you type in Controller1, Controller2 get automatically updated. This is because using $watch we keep on updating the $rootScope.
$apply
There might be many instances, when value of a scope variable might change outside of angular scope. e.g browser dom events, jquery document ready event, setTimeout, 3rd party libraries or any other such external factors. To sync the $scope back we use $apply function. Lets demonstrate this using an example
var mainMod = angular.module('MainApp', []);
mainMod.controller('MainCtrl', ['$scope','$rootScope',
function ($scope,$rootScope) {
$scope.update = function(){
setTimeout(function(){
$scope.text1 = 'New Text';
$scope.$apply(); //removing this New Text won't be updated
},500);
}
}
]);
<body ng-app='MainApp'>
<div ng-controller='MainCtrl'>
<div>
<div>Controller1</div>
<input type='text' ng-model='text1'/>
<br/>
Text: {{text1}}
<br/>
<input type='button' ng-click='update();' value='Update Outside' />
</div>
</div>
</body>
In the above example, setTimeout is used simulate an event which is outside angular $scope. If in the above example we remove $scope.$apply() the text is not updated.
More details here
$scope Events $on,$emit,$broadcast
$scope and $rootScope object exposes many events which we can use to transmit data.
$on: This is used to listen to any event fired.
$scope.$on('test_event',function(event){
});
$emit: This is used to fire an event to all its parent scopes, till the $rootScope
$scope.$emit('test_event');
$broadcast: This is used to fire an event to all its child scopes.
$scope.$broadcast('test_event');
Let see an example to see how these work.
var mainMod = angular.module('MainApp', []);
mainMod.controller('MainCtrl', ['$scope',
function ($scope) {
$scope.name = 'Ctrl1′;
$scope.update = function(){
$scope.$emit('emit_event');
}
$scope.update2 = function(){
$scope.$broadcast('broadcast_event');
}
$scope.$on('emit_event',function(event){
$scope.event = 'emit event from ' + event.targetScope.name
})
$scope.$on('broadcast_event',function(event){
$scope.event = 'broadcast event from ' + event.targetScope.name
})
}
]);
mainMod.controller('ChildCtrl',function($scope){
$scope.name = 'Ctrl2′;
$scope.update = function(){
$scope.$emit('emit_event');
}
$scope.update2 = function(){
$scope.$broadcast('broadcast_event');
}
$scope.$on('emit_event',function(event){
$scope.event = 'emit event from ' + event.targetScope.name
})
$scope.$on('broadcast_event',function(event){
$scope.event = 'broadcast event from ' + event.targetScope.name
})
});
<body ng-app='MainApp'>
<div ng-controller='MainCtrl'>
<div>
<div>Controller1</div>
Event: {{event}}
<br/>
<input type='button' ng-click='update();' value='Emit Event' />
<input type='button' ng-click='update2();' value='Broadcast Event' />
<br/>
<div ng-controller='ChildCtrl'>
<div>Child Controller</div>
Event: {{event}}
<br/>
<input type='button' ng-click='update();' value='Emit Event' />
<input type='button' ng-click='update2();' value='Broadcase Event' />
</div>
</div>
</div>
</body>
In the above example, we create 2 controllers one controller is child of another. $scope also becomes child of another and we can clearly see difference between $emit and $broadcast.
All these event functions are also available on $rootScope as well.
$rootScope $emit/$broadcast
As we saw above $emit is used to send data upwards and $broadcast is used to send data downwards. So in $rootScope, $emit won’t make any sense since there is no parent to $rootScope. But there is a small difference in $rootScope.$emit, it only send events to $rootScope.$on listeners. If you used $rootScope.$broadcast, it send event to all listeners ($rootScope.$on and $scope.$on)
We can see more detailed explanation about Scopes here