Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Directive listen to controller variable change

Just starting out in AngularJS and trying to figure out the best practice for listening to events when a variable within a controller changes. The only way I have gotten it to work is with an emit, as follows.

For example:

var app = angular.module("sampleApp", [])

app.controller("AppCtrl", function($scope){
  $scope.elements = [
    {
        name: "test"
    }
  ]

  $scope.addElement = function() {
      $scope.elements.push({
          name: "test" + $scope.elements.length
      })
      $scope.$emit('elementsChanged', $scope.elements);
  }
})

app.directive('render', function() {
  var renderFunc = function() {
      console.log("model updated");
  }
  return {
      restrict: 'E',
      link: function(scope, element, attrs, ngModel) {
         scope.$on('elementsChanged', function(event, args) {
              renderFunc();
         })
      }
  }
})

This seems a bit wonky, and I feel like I'm working against the point of angular. I've tried to have a $watch on a model, but that doesn't seem to be working. Any help on this would be very appreciated, thanks!

like image 839
dardo Avatar asked Oct 21 '22 22:10

dardo


1 Answers

I'm going to assume you're using unstable Angular, because $watchCollection is only in the unstable branch.

$watchCollection(obj, listener)

Shallow watches the properties of an object and fires whenever any of the properties change (for arrays, this implies watching the array items; for object maps, this implies watching the properties). If a change is detected, the listener callback is fired.

The 'Angular' way of doing this would be to watch an attribute in your directive.

<render collection='elements'></render>

Your directive

app.directive('render', function() {
  var renderFunc = function() {
      console.log("model updated");
  }
  return {
      restrict: 'E',
      link: function(scope, element, attrs) {
         scope.$watchCollection(attrs.collection, function(val) {
           renderFunc();
         });
      }
  }
})

If you're doing this on stable angular, you can pass true as the last argument to scope.$watch, which will watch for equality rather than reference.

$watch(watchExpression, listener, objectEquality)

objectEquality (optional) boolean Compare object for equality rather than for reference.

What's happening here is the collection attribute on the DOM element specifies which property on our scope we should watch. The $watchCollection function callback will be executed anytime that value changes on the scope, so we can safely fire the renderFunc().

Events in Angular should really not be used that often. You were right in thinking there was a better way. Hopefully this helps.

like image 60
Adam Avatar answered Oct 23 '22 15:10

Adam