Last Updated: July 15, 2016
·
4.442K
· sirtophamhatt

AngularJS Mediator Pattern

Synopsis

A standard Mediator Pattern applied to AngularJS which does not use $broadcasts or $emits.

  • Avoids unnecessary injecting and exposing of $scope onto one's view where controllerAs 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

Plnkr

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>"
          };    
     } );

1 Response
Add your 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
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