I have a simple Pipe that filter an array of students. Here's the code (Plnkr)
import {Pipe} from 'angular2/core';
@Pipe({
name: 'sortByName',
pure: false
})
export class SortByNamePipe {
temp = [];
// i = 0;
transform (value, [queryString]) {
// console.log(this.i++);
// console.log(value, queryString);
// This does not work
this.temp = value.filter((student)=>(student)=>student.name.includes(queryString)))
return value.map(function(val){ return val.name.toUpperCase()});
// This works
// this.temp.length = 0;
// this.temp.push(...value.filter((student)=>student.name.includes(queryString)))
// return this.temp;
}
}
As you can see in Plnkr, Angular throws an error using the first method.
EXCEPTION: Expression 'students | sortByName:queryElem.value in HelloWorld@7:6' has changed after it was checked. Previous value: 'SON,DAVID'. Current value: 'SON,DAVID' in [students | sortByName:queryElem.value in HelloWorld@7:6]
Why?
Angular cannot make certain optimizations for a stateful pipe, than it can for a stateless (or pure) pipe. For example, if a pipe is stateless, then it follows that the output of the filter only depends on its inputs (left | pipe:args). As long as 'left' or 'args' hasn't changed, then the output will not change. This allows AngularJS to safely skip the execution of the pipe when the inputs haven't changed.
For a stateful pipe, the output of the pipe can change, even for the same inputs.
The error is telling you that the array reference has changed, after it has been checked following the first round of change detection:
... has changed after it was checked.
Previous value: 'SON,DAVID'. Current value: 'SON,DAVID'...
I've modified your first example to preserve the array reference:
// This now works
var $this = this; // save this
$this.temp.length = 0;
var tmp = value.filter((student)=>student.name.includes(queryString));
tmp.forEach(function (val) {$this.temp.push(val);});
return $this.temp;
[Edit]
As Mark pointed out, the error only occurs during development mode. If you change to production mode the error goes away, and the code works as expected.
[Explanation]
Apparently, in dev mode, angular will check your bindings twice to make sure they're not changing.
https://github.com/angular/angular/issues/6006
https://github.com/angular/angular/issues/6005
The problem is that when a binding changes after the first round of change detection, it will not trigger a new round of change detection. This is undesirable because the binding will not be updated until some future round of change detection. To ensure that this does not happen, Angular checks the bindings twice in development mode, and raises a run-time error when changes are detected.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments