Niels Steenbeek
Niels Steenbeek

Reputation: 4834

Angularjs watch input binding change for Array when using ControllerAs

I have an AngularJs component having bindings to heroes, which is an array. How to watch this input for array changes? I tried $scope.watch("heroes", ...) and $onChanges, but didn't work so far.

bindings: {
    heroes: '<',
}

Here is my plunker: https://plnkr.co/edit/J8xeqEQftGq3ULazk8mS?p=preview

Upvotes: 2

Views: 2378

Answers (2)

Niels Steenbeek
Niels Steenbeek

Reputation: 4834

The ControllerAs structure needs a special watch expression, since the attributes are not on the $scope.

//This one works and is the best one (> AngularJs 1.5)
$scope.$watch("$ctrl.heroes.length", function () {
  console.log("ControllerAs syntax"); // Triggers once on init
});

//This one works as well
var ctrl = this;
$scope.$watch(() => {
  return ctrl.heroes.length;
}, (value) => {
  console.log("complex watch"); // Triggers once on init
});

See example here: https://plnkr.co/edit/J8xeqEQftGq3ULazk8mS?p=preview

Upvotes: 4

gh9
gh9

Reputation: 10703

The issue occurs because $scope.$watch by default doesn't deeply watch objects. Which means since you never destroy/recreate your array, the reference doesnt really change therefore $scope.$watch doesnt see any change. If you watched heroes.length, that primitive would change and your $scope.$watch would fire the corresponding listening function. By using $scope.$watch with the true option you are telling the angular engine to deeply watch all properties. This is pretty intensive to do for large objects because $scope.$watch using angular.copy to track changes

If you were to use $scope.$watchCollection angular would create a shallow copy and would be less memory intensive. So I feel your 3 main options are

Watch heroes.length , add true or use $watchCollection

I feel that using heroes.length would be your best bet, so the code would look like

$scope.$watch('heroes.length',function(){});

The other two options are described below

$scope.$watch('heroes',function(){ //do somthing },true)

or

$scope.$watchCollection

The benefit of using watchCollection is, that it requires less memory to deeply watch an object.

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 obj collection is observed via standard $watch operation and is examined on every call to $digest() to see if any items have been added, removed, or moved. The listener is called whenever anything within the obj has changed. Examples include adding, removing, and moving items belonging to an object or array.

Upvotes: 0

Related Questions