Двусторонняя привязка Angular 7: канал, принимающий массив в качестве аргумента, не работает должным образом

Я написал канал Angular 7, который принимает 2 аргумента: массив для фильтрации и массив соответствующих фильтров.

import { Pipe, PipeTransform } from '@angular/core';

import { Order } from '../models';

@Pipe({
  name: 'filterOrdersByDate'
})
export class CapacityOrderPipe implements PipeTransform {

  transform(orders: Order[], periods: string[]): Order[] {

    if (!orders) return [];
    if (!periods.length) return orders;

    return orders.filter(function(order: Order) {

      for (var i=0; i<periods.length; i++) if (order.crossId.indexOf(periods[i])>-1) return true;
      return false;

    });

  }

}

заказы — это массив заказов, как определено в модели Order. Каждый заказ имеет свойство crossId. Это массив строк, представляющих начальную дату.

В моем component.ts у меня есть этот метод для добавления/удаления даты из массива периодов:

toggleOrder(date: string) {
  let i = this.filters.orders.indexOf(date);
  (i<0)? this.filters.orders.push(date) : this.filters.orders.splice(i, 1);
}

и это задействованный код component.html:

<mat-list class="list">
  <mat-list-item *ngFor="let o of (data.orders | filterOrdersByDate : filters.orders)">
    <mat-divider></mat-divider>
    <h3 mat-line>Order: {{o.group}}-{{o.number}}</h3>
    ...
   </mat-list-item>
</mat-list>

...

<div *ngFor="let f of filters">
<mat-checkbox color="primary" [indeterminate]="false" (change)="toggleOrder(f.date)">{{f.date}}</mat-checkbox>
</div>

Когда я переключаю флажок в component.html, метод toggleOrder() добавляет или удаляет дату в массиве фильтров. Итак, я ожидаю, что канал будет фильтровать массив data.orders. К сожалению, это НЕ работает. Я потратил 2 часа на поиск решения и обнаружил, что если передать длину массива фильтров в канал, все работает как положено. Итак, кажется, что Angular установил двустороннюю привязку к длине массива фильтров, но не к самому массиву фильтров.

Как это работает? Я ожидаю, что Angular устанавливает двустороннюю привязку ко всем свойствам, определенным в классе компонента: строкам, массивам, числам и т. д. Но канал не прослушивает изменения в содержимом массива. Только если я передаю длину массива в канал, он работает. Но если у меня есть канал, который принимает строку для фильтрации данных вместо массива, он работает отлично.


person Alexandro    schedule 29.03.2019    source источник


Ответы (1)


Если вы посмотрите на документы Angular, там говорится о подобных сценариях. Это препятствует работе каналов с массивами таким образом из-за их низкой производительности.

То, чего вы пытаетесь достичь, как есть, одним из двух способов.

Вы можете обновить свою трубу, чтобы она была «нечистой» трубой:

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

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

toggleOrder(date: string) {
  let i = this.filters.orders.indexOf(date);
  (i<0)? this.filters.orders.push(date) : this.filters.orders.splice(i, 1);
  this.filters.orders = this.filters.orders.slice(0);
}

Однако, как было сказано изначально, это не самый оптимальный способ выполнения этой задачи. Я бы придерживался рекомендаций Angular и вместо этого переместил этот канал в метод, который можно вызвать из вашего метода toggleOrder.

Команда Angular и многие опытные разработчики Angular настоятельно рекомендуют переносить логику фильтрации и сортировки в сам компонент. Компонент может предоставлять свойство filteredHeroes или sortedHeroes и контролировать, когда и как часто выполнять вспомогательную логику. Любые возможности, которые вы бы поместили в конвейер и использовали в приложении, можно записать в службу фильтрации/сортировки и внедрить в компонент.

person peinearydevelopment    schedule 29.03.2019