Reputation: 9627
I'm writing a simple todo app to learn Angular 2. I noticed that using pipes break the update behavior.
I have the following template
<input type="text" placeholder="Search" #queryBox (keyup)="query=queryBox.value">
<ul class="task-list">
<task-item *ng-for="#task of tasks | filter:containsString:query" [task]="task" (onDelete)="delete($event)"></task-item>
</ul>
and when I click on the delete button, the underlying data model is changed but this change is not reflected in the UI. I have determined it's because the filter pipe doesn't get called. If I change the above line to
<task-item *ng-for="#task of tasks" [task]="task" (onDelete)="delete($event)"></task-item>
then things like add, delete works again, but obvious I don't get filtering. Why would adding pipes break the update behavior of this binding?
Upvotes: 3
Views: 7419
Reputation: 364747
By default, pipes are stateless/pure. If their inputs don't change, the pipes are not executed during a change detection cycle. For this question, where we have
"#task of tasks | filter:containsString:query"
tasks
, containsString
and query
are the inputs, and pipe filter
is stateless/pure. tasks
is an array (reference).
When a task is deleted, the array reference doesn't change – the tasks
input to the pipe doesn't change – hence the stateless/pure pipe is not executed.
If we make the pipe stateful with pure: false
, then the pipe will be evaluated on every change detection cycle – even if the inputs do not change.
You may also need to either
onPush
change detection strategy for the component (if possible), ortransform()
method such that it returns the same array (reference).These alternatives are explained in detail in this answer (I don't want to repeat all of that here).
Upvotes: 1
Reputation: 817
That's because by default Pipes are stateless (they render UI just once).
You have to add :
@Pipe({
selector: ...,
pure: false
})
When you set 'pure' to false, Angular updates the data inside the pipe each cycle.
Upvotes: 2