dhgljg
Last Updated: October 12, 2017
·
26.75K
· joseym

AngularJS - Watch for changes in a service.

I tend to break my applications up into 3 main groups:

  • App Module (primary app controllers)
  • App Directives
  • App Services

I usually put much of my logic into services that can be used within the app controllers and directives, but only recently discovered that $watch can be used on more than just your app scope!

In a directive I was working on I make a ngResource request to get a file tree; the logic for this request is inside a service I've named Tree.

There are actions that should cause the tree to refresh, but since it was in a service I was having trouble getting that to work well.

Enter $watch

I like watch. Watching for changes can make it pretty seamless when you need to fire actions based on those changes without muddying your markup with ng-change and ng-click.

So here's a dumbed down version of my application:

var App = app.module('ExampleApp', []);

/**
  * Dummy Service
  */
App.service('Tree', function(){
  this.rebuild = false;

  this.Build = function(cb){
    // resource request to get tree  hierarcy
    cb(response);
  };

  return this;
});

App.directive('treeView', function(Tree){
  return {
    restrict: 'A',
    link: function(scope, elem, attrs){
      scope.data = []; // The directive template will loop this data

      // Watch for changes in the service
      scope.$watch(function(){
        return Tree.rebuild;
      }, function(newVal, oldVal){
        if(newVal) Tree.Build(function(response){ scope.data = response; Tree.rebuild = false; });
      }
    };

});

So instead of watching a key on the scope i'm watching a function that returns the service data.

Why is that cool?

Now, from ANYWHERE in my app (say a user controller, that really doesn't even come close to touching the directive) I can toggle Tree.rebuild and the directive will update.

App.controller('UserCtrl', function($scope, Tree){
  if($scope.user.newFile) Tree.rebuild = true;
})

That simple call will now update the directive, and I didn't even have to resort to $rootScope assignments!