简体   繁体   中英

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!

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM