View on GitHub

eburley.github.com

code and stuff

angularjs.org watch, on pub sub, and you.

A team I work on has been using angularjs.org’s various watch and event systems for more than half a year now, and I wanted to put out some best practices that we’ve learned from painful experience.

When to use a watch:

When NOT to use a watch:

Best practices around watches:

$scope.$watch(function(){return SomeService.stateValueGetter()},
    function(newValue,oldValue){});

just do this:

$scope.$watch(SomeService.stateValueGetter,
    function(newValue,oldValue){});

When to use pub/sub:

When NOT to use pub/sub:

Best practices around pub/sub:

// an example channel service that lets consumers
// subscribe and publish for nuclear reactor meltdowns
 
var CoreReactorChannel = function($rootScope) {
 
    // local constants for the message ids.  
    // these are private implementation detail
    var ELEVATED_CORE_TEMPERATURE_MESSAGE = "elevatedCoreMessage";
 
    // publish elevatedCoreTemperature
    // note that the parameters are particular to the problem domain
    var elevatedCoreTemperature = function(core_id, temperature) {
        $rootScope.$broadcast(ELEVATED_CORE_TEMPERATURE_MESSAGE,
            {
                core_id: core_id,
                temperature: temperature
            });
    };
 
    // subscribe to elevatedCoreTemperature event.
    // note that you should require $scope first 
    // so that when the subscriber is destroyed you 
    // don't create a closure over it, and te scope can clean up. 
    var onElevatedCoreTemperature = function($scope, handler) {
        $scope.$on(ELEVATED_CORE_TEMPERATURE_MESSAGE, function(event, message){
            // note that the handler is passed the problem domain parameters 
            handler(message.core_id, message.temperature);
        });
    };

    // other CoreReactorChannel events would go here.

    return {
        elevatedCoreTemperature: elevatedCoreTemperature,
        onElevatedCoreTemperature: onElevatedCoreTemperature
    };
};

 
//Usage elsewhere in the application
var MyController = function($scope, CoreReactorChannel){
    // Handle core temperature changes
    var onCoreTemperatureChange = function(core_id, temperature){
        console.log(core_id, temperature);
    }
    
    // Let the CoreReactorChannel know the temperature has changed
    $scope.changeTemperature = function(core_id, temperature){
        CoreReactorChannel.elevatedCoreTemperature(core_id, temperature);
    }
 
    // Listen for temperature changes and call a handler
    // Note: The handler can be an inline function
    CoreReactorChannel.onElevatedCoreTemperature($scope, onCoreTemperatureChange);
};