AngularJS Mediator Pattern
Synopsis
A standard Mediator Pattern applied to AngularJS which does not use $broadcasts or $emits.
- Avoids unnecessary injecting and exposing of
$scopeonto one's view wherecontrollerAsis preferred. - Circumvents using
$rootScopeto update viewmodels existing on sibling$scopepaths. - Does not trigger additional
$applyor$digestcycles. - Employs lodash for better cross-browser performance.
-
Mediator.subscribereturns a function to deregister the subscriber, similar to Angular's$scope.$onimplementation.
( 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
pdabrowski
11.89K
endel
3.878K
Related Tags
#design patterns
#javascript
#mediator
#angularjs
#lodash
#$scope
#$broadcast
#$event
#$emit
#$rootscope
#controlleras
Did you know?
JavaScript on a page runs with the privileges of that origin. One altered library, tag manager, or snippet can read inputs, change what people see, and call your APIs as the user.
Security insights from Cside
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#