Let's start off this one with when not to use $scope events
($broadcast and $emit). These are an overused and very
difficult-to-track practice that can most often be avoided.
You will most often never use scope events. If you have been following along in the guide, you will see that:
- You no longer need them to communicate with a child controller, since we are no longer using ng-controller.
- You no longer need them to communicate to child components. Use isolate scope components and attributes to communicate with them instead.
- You no longer need them to communicate from a child component to a
parent controller. Since all of your views are components
you have
&attributes (named something likeon-xyz) to allow parents to subscribe to "events" that the component "emits". - You shouldn't need them to communicate to services - simple method calls to the service will do.
When To Actually Use Scope Events
The only case that I have found that is valid for $scope events
is to allow services to broadcast important events to the rest of the
app. For example, maybe the user has been logged out due to a timeout:
angular.module( 'myApp' ).factory( 'UserService', function( $rootScope, Event ) {
'use strict';
// ...
function userSessionExpired() {
$rootScope.$broadcast( Event.USER_LOGGED_OUT );
}
} );
Event.js - All Events are Global
Event.js is a place to put all of the available global events for your
app, to make sure that you never accidentally duplicate an event value.
If you did, it could cause your app to accidentally respond to incorrect
events.
Event.js looks something like this:
angular.module( 'myApp' ).constant( 'Event', {
USER_LOGGED_OUT: 0,
SOME_OTHER_EVENT: 1,
...
} );
You may want to add a test for Event.js to make absolutely sure that
there are never any duplicate event values in the file:
describe( 'Event', function() {
var Event;
beforeEach( module( 'heroes' ) );
beforeEach( inject( function( $injector ) {
Event = $injector.get( 'Event' );
} ) );
it( 'should have no duplicate event values', function() {
var set = {};
for( var eventProp in Event ) {
if( set[ eventProp ] === true ) {
throw new Error( 'Duplicate event value found at key: ' + eventProp );
}
set[ eventProp ] = true;
}
} );
} );
Subscribing to Service-Level Events from Controllers
Important point: when a controller subscribes to the event, it should be subscribed to on the local scope so that you don't need to worry about unregistering the listener when the scope is destroyed.
(If you were to listen for it on the $rootScope, it would cause your
controller to stay alive even after Angular tried to $destroy() it.)
angular.module( 'myApp' ).controller( 'MyPageController', MyPageController );
function MyPageController( $scope, Event ) {
'use strict';
$scope.$on( Event.USER_LOGGED_OUT, handleLogout );
/**
* @private
*/
function handleLogout() {
// ...
}
}