Как активировать трубу в Angular при изменении модели? - PullRequest
0 голосов
/ 18 июня 2020

У меня есть фильтрующая труба, которую я использую для фильтрации массива объектов. Трубка фильтра имеет инъекцию зависимости службой. В сервисе есть данные модели filterService.data.

Как активировать трубу в шаблоне только при изменении модели в сервисе?

@Pipe({
    name: 'filter',
})
export class FilterPipe implements PipeTransform {
    constructor(private filterService: FilterService) {}

    transform(array: any, start?: any, end?: any): any {}
}

Использование:

 *ngFor="let item of response | filter"

Ответы [ 3 ]

3 голосов
/ 18 июня 2020

Труба Angular по умолчанию чистая. Он запускает обновление только при изменении любого из входных параметров . Это единственный способ «активировать» канал (обновить его результат). Любая служба зависимостей, которую использует канал, является внутренней и не имеет отношения к потребителю канала, который отвечает за повторный рендеринг его представления после обнаружения изменений в данных, переданных в канал.

Итак, в вашем примере, только когда Angular обнаруживает изменение в array, start или end, затем активирует канал. Еще раз, изменение этих параметров - единственный способ контролировать повторное применение трубы. Таким образом, правильный способ обновления трубы после изменения модели - распространить изменение через любой из входных параметров, введенных в трубу. Затем внутри канала вы можете применить службу преобразования к данным для получения желаемого результата. Не загружайте службу какими-либо данными вне этого потока, иначе она никогда не будет обнаружена функцией обнаружения изменений. Заставить канал зависеть от внешних данных, как это, может иметь побочные эффекты, нарушая правило, согласно которому чистый канал должен быть чистой функцией.

Скажем, если вы хотите добавить больше критериев сортировки к фильтру, вы должны изменить ваш канал выглядит следующим образом:

 transform(array: any[], start?: any, end?: any, orderBy?: string, descending?: boolean): any[] {}

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

Теперь посмотрите на array: вместо опции для передачи службе фильтрации (которая обычно является скалярным значением) первый параметр канала всегда указывает цель, на которую действует канал, обычно массив (нескалярный). При изменении этого массива труба тоже должна быть активирована, но есть загвоздка. Поскольку массивы передаются по ссылке, даже если вы изменяете исходный массив, если изменение присутствует, массив по-прежнему считается таким же, поэтому никаких изменений в отношении канала не обнаруживается. Поэтому, когда вы обновляете исходный массив, например, при получении новой страницы с элементами, если вы хотите запустить обновление, важно изменить сам массив, а не просто изменить его содержимое:

  array = [...array, newItem];  // NOT array.push(newItem);

Придерживайтесь этого Правило, тогда ваш канал будет вести себя хорошо.

Каналы - это удобный способ настроить вид, но старайтесь не злоупотреблять ими. Перенесите задачу преобразования в компонент рендеринга logi c (или, лучше, используя общую службу), как рекомендовано в документации Angular :

Команда Angular и многие опытные Angular разработчики настоятельно рекомендуют перенести логи фильтрации и сортировки c в сам компонент.

Таким образом, у вас будет больше контроля над тем, как и когда вы представляете данные, и вы можете повысить эффективность, поскольку вы можете отфильтровать подмножество данных для оптимального рендеринга, вместо того, чтобы подключать их к дорогим каналам и обратно, как мы все привыкли.

1 голос

Быстрое решение - нечистая труба, будет обновляться при каждом изменении, даже если это будет ненужным:

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

Но это решение неприемлемо с точки зрения производительности.

Чистые трубы update после изменения значения или аргументов, но если ссылка на массив не изменилась, pipe не будет обновлен. Вы можете попробовать обновить ссылку на массив после изменения массива: response = [...response]

0 голосов
/ 18 июня 2020

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

@Pipe({
  name: 'filter',
})
export class FilterPipe implements PipeTransform {
  constructor(private filterService: FilterService) {}

  transform(array: any, start?: any, end?: any): any {
    if (filterService.applyTransform) {
      // apply transformation
    } else {
      return array;
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...