Значение ошибки изменилось после проверки (Stateful Pipe в Angular2)

У меня есть простая труба, которая фильтрует массив студентов. Здесь код (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;
  }
}

Как вы можете видеть в Plnkr, Angular выдает ошибку с использованием первого метода.

EXCEPTION: Expression 'students | sortByName:queryElem.value  in [email protected]:6' has changed after it was checked. Previous value: 'SON,DAVID'. Current value: 'SON,DAVID' in [students | sortByName:queryElem.value  in [email protected]:6]

Почему?

Ответ 1

Angular не может выполнить определенную оптимизацию для канала с состоянием, чем он может для безгосударственного (или чистого) канала. Например, если канал не имеет состояния, то следует, что выход фильтра зависит только от его входов (left | pipe: args). Пока "left" или "args" не изменились, результат не изменится. Это позволяет AngularJS безопасно пропускать выполнение трубы, когда входы не изменились.

Для трубы с постоянным током выход трубы может меняться даже для тех же самых входов.

Ошибка сообщает вам, что ссылка на массив изменилась после того, как она была проверена после первого раунда обнаружения изменений:

... has changed after it was checked. 
Previous value: 'SON,DAVID'. Current value: 'SON,DAVID'...

Я изменил свой первый пример, чтобы сохранить ссылку на массив:

// 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;

[изменить]

Как отметил Марк, ошибка возникает только в режиме разработки. Если вы перейдете в режим производства, ошибка исчезнет, ​​и код работает как ожидалось.

[Пояснение]

По-видимому, в режиме dev angular дважды проверит ваши привязки, чтобы убедиться, что они не меняются.

https://github.com/angular/angular/issues/6006

https://github.com/angular/angular/issues/6005

Проблема заключается в том, что когда привязка изменяется после первого раунда обнаружения изменений, она не будет запускать новый раунд обнаружения изменений. Это нежелательно, потому что привязка не будет обновляться до некоторого будущего раунда обнаружения изменений. Чтобы убедиться, что этого не происходит, angular дважды проверяет привязки в режиме разработки и повышает время выполнения при обнаружении изменений.

Обновлено Plunkr