jz87
jz87

Reputation: 9627

How does Angular2's pipes work with data binding?

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

Answers (2)

Mark Rajcok
Mark Rajcok

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

  • specify the onPush change detection strategy for the component (if possible), or
  • implement the pipe's transform() 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

Romain
Romain

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

Related Questions