AngularJS Mediator Pattern
Synopsis
A standard Mediator Pattern applied to AngularJS which does not use $broadcast
s or $emit
s.
- Avoids unnecessary injecting and exposing of
$scope
onto one's view wherecontrollerAs
is preferred. - Circumvents using
$rootScope
to update viewmodels existing on sibling$scope
paths. - Does not trigger additional
$apply
or$digest
cycles. - Employs lodash for better cross-browser performance.
-
Mediator.subscribe
returns a function to deregister the subscriber, similar to Angular's$scope.$on
implementation.
( function( angular , _ ) {
function MediatorService( $log ) {
var Mediator = {};
var channels = {};
var subscriberId = 0;
Mediator.publish = function( channel , publisher , data ) {
if ( ! hasSubscriber( channel ) ) {
return;
}
var subscribers = channels[ channel ];
_.map( subscribers, function( subscriber ) {
try {
subscriber.callback( data );
} catch ( e ) {
$log.error( e , publisher , subscriber.name )
}
} );
};
Mediator.subscribe = function( channel , subscriber , callback ) {
if ( ! hasSubscriber( channel ) ) {
channels[ channel ] = [ ];
}
channels[ channel ].push( {
"callback" : callback ,
"name" : subscriber ,
"subscriberId" : ++subscriberId
} );
return function( ) {
unsubscribe( subscriberId );
};
};
function hasSubscriber( channel ) {
return _.has( channels , channel );
}
function unsubscribe( subscriberId ) {
channels = _.map( channels , function( channel ) {
return _.filter( channel , function( subscriber ) {
return subscriber.subscriberId !== subscriberId;
});
});
}
return Mediator;
}
angular
.module( "app" )
.factory( "Mediator" , [ "$log" , MediatorService ] );
} ) ( angular, _ );
Implementation
HTML
<div data-first=""></div>
<div data-second=""></div>
JS
angular
.module( "app" , [ ] )
.factory( "Mediator" , [ "$log", MediatorService ] )
.directive( "first" , function( ) {
return {
controller: function( ) {
this.name = "First";
},
controllerAs: "first",
template: "<p ng-bind='first.name'></p><div data-third></div>"
};
} )
.directive( "second" , function( Mediator ) {
return {
controller: function( ) {
this.name = "Second";
this.publishNewName = Mediator.publish.bind( this , "NewName" , "second" , this.name );
},
controllerAs: "second",
template: "<a ng-bind='second.name' ng-click='this.publishNewName( )'></a>"
};
} )
.directive( "third" , function( Mediator ) {
return {
controller: function( ) {
this.name = "Third";
var unsubscribe = Mediator.subscribe( "NewName" , "third" , setName.bind( this ) );
function setName(name) {
this.name = name;
unsubscribe( );
}
},
controllerAs: "third",
template: "<p ng-bind='third.name'></p>"
};
} );
Written by Matt Duggan
Related protips
1 Response
Why did you reinvent $broadcast/$emit and $on? What's better about this method than using events?
over 1 year ago
·
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
#Design patterns
Authors
Related Tags
#design patterns
#javascript
#mediator
#angularjs
#lodash
#$scope
#$broadcast
#$event
#$emit
#$rootscope
#controlleras
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#