Настройте обнаружение изменений для выполнения глубокого сравнения объектов вместо проверки равенства ссылок в Angular2.

Я создал канал фильтра для фильтрации массива объектов. Этот канал получает объект filterArgs, который содержит некоторые свойства, на основе которых элементы должны быть отфильтрованы.

@Pipe({
    name: 'filter'
})
export class FilterPipe implements PipeTransform {
    transform(items: Item[], filterArgs: any): Item[] {
        return items.filter(item => ...);
    }
}

Кроме того, у меня есть несколько полей ввода, в которых пользователи могут устанавливать аргументы фильтра. Я связываю свойства объекта filterArgs напрямую и применяю фильтр к таким элементам:

<input type="date" [(ngModel)]="filterArgs.dateFrom">
<input type="date" [(ngModel)]="filterArgs.dateTo">

<ul>
    <li *ngFor="let item of items | filter:filterArgs>...</li>
</ul>

В моем компоненте объект filterArgs определяется следующим образом (схематично):

public filterArgs: any;

ngOnInit() {
    this.filterArgs = {
        dateFrom = undefined,
        dateTo = undefined
    };
}

Итак, проблема в том, что фильтр не применяется при изменении одного из полей ввода. Насколько я понял обнаружение изменений Angular, это связано с тем, что ссылка на объект filterArgs не изменяется, и поэтому Angular не обнаруживает никаких изменений. Это ожидаемое поведение и дизайн.

Теперь мой вопрос: каков предлагаемый способ решения этой проблемы?

Наивным подходом было бы создание нового объекта filterArgs каждый раз при изменении поля ввода, чтобы ссылка на этот объект обновлялась. В этом случае сработает обнаружение изменений Angular. Но должен быть лучший способ сделать это. Я бы подумал, что мог бы аннотировать свойство filterArgs каким-то атрибутом, который сообщает Angular выполнять «глубокое сравнение объектов» для обнаружения изменений.


person M.E.    schedule 05.05.2016    source источник


Ответы (1)


Для компонентов и директив вы можете реализовать DoCheck для обнаружения пользовательских изменений, но для каналов это не поддерживается.

В качестве альтернативы вы можете «оптимизировать» трубу, используя

@Pipe({
    name: 'filter',
    pure: false
})

И вернуть кешированный результат, когда фильтр не изменился

person Günter Zöchbauer    schedule 05.05.2016
comment
Спасибо за Ваш ответ. Нечистая труба не подходит для меня из-за соображений производительности. Мне также не нужно обнаружение изменений для самих отфильтрованных элементов. Пользовательское обнаружение изменений необходимо только для объекта filterArgs. Думаю, я выберу неизменяемый объект filterArgs, как указано в этом сообщении в блоге. . (т.е. создавать новый объект filterArgs каждый раз, когда обновляется поле ввода) - person M.E.; 05.05.2016
comment
Я также думаю, что это лучший вариант для вашей ситуации. - person Günter Zöchbauer; 05.05.2016