Christopher Inch
Christopher Inch

Reputation: 99

How do I update a filtered array in an AngularJS directive?

I'm new to AngularJS. I've built a directive that uses an Isolate Scope (=) on an array called "todos". I then filter the todos array, and call it filteredArray. My "todos" element is updated using bidirectional binding, but I do not know what must be done to bind the update of todos to filteredArray.

I've set up a fiddle for my experimenting here: http://jsfiddle.net/apkk3rjc/ You can even see I've tried to set up a simple $watch() on line 50 of my JS but it doesn't seem to trigger beyond the first load.

To be clear: I don't need two-way binding back to my controller, but I do need the filteredTodos to update automatically when a change to todos is made.

Here is my directive:

todoApp.directive('todoList', ['filterFilter', function(filterFilter) {
return {
    restrict: 'E',
    templateUrl: 'todo-list.html',
    scope: {
        todos: '='
    },
    link: function (scope, element, attrs) {
        // scope.todos is bound
        // scope.filteredTodos is not!
        scope.filteredTodos = filterFilter(scope.todos, { completed: false });
    }
};
}]);

Upvotes: 0

Views: 869

Answers (1)

Christopher Inch
Christopher Inch

Reputation: 99

I have found the answer to my own question. Two things need to be applied:

First, scope.filteredTodos won't be bound automatically, so it must be recalculated whenever scope.todos is modified. So we add a $watch to the array.

My original $watch looked like this and is wrong:

// Watch the entire array. DOESN'T FIRE ON NEW ITEMS
scope.$watch('todos', function () { ... });

This does not work because watching the entire array doesn't track changes. In the end, I simply watched the length of the array.

// Watch the array length. Works when new items are added! :)
scope.$watch('todos.length', function () { ... });

Alternatively, you can set a third parameter, 'deep' to true, but this comes with a lot of overhead, especially if your array is very large. However, if you want to watch each item of your array for changes, this will be the only way.

// Watch the entire array with deep analysis. Costly, but works.
scope.$watch('todos', function () { ... }, true);

So since I'm just looking for new elements in my array, I went with watching 'todos.length'.

Upvotes: 1

Related Questions