Как определить, когда значение @Input() изменяется в Angular?
у меня есть родительский компонент (CategoryComponent), дочернего компонента (videoListComponent) и ApiService.
у меня большая часть этого работает нормально, т. е. каждый компонент может получить доступ к api JSON и получить свои соответствующие данные через наблюдаемые.
В настоящее время компонент списка видео просто получает все видео, я хотел бы отфильтровать это только видео в определенной категории, я достиг этого, передав categoryId ребенку через @Input()
.
CategoryComponent.HTML-код
<video-list *ngIf="category" [categoryId]="category.id"></video-list>
это работает, и когда родительская категория CategoryComponent изменяется, значение categoryId передается через@Input()
но затем мне нужно обнаружить это в VideoListComponent и повторно запросить массив видео через APIService (с новым categoryId).
в AngularJS я бы сделал $watch
на переменную. Как лучше с этим справиться?
7 ответов
на самом деле, есть два способа обнаружения и действия, когда входные изменения в дочернем компоненте в angular2+ :
-
можно использовать метод жизненного цикла ngOnChanges () как уже упоминалось в старых ответах:
@Input() categoryId: string; ngOnChanges(changes: SimpleChanges) { this.doSomething(changes.categoryId.currentValue); // You can also use categoryId.previousValue and // categoryId.firstChange for comparing old and new values }
Ссылки На Документацию:ngOnChanges, SimpleChanges, SimpleChange
Пример демонстрации: посмотрите на этот plunker -
кроме того, вы также можете использовать входное свойство setter следующим образом:
private _categoryId: string; @Input() set categoryId(value: string) { this._categoryId = value; this.doSomething(this._categoryId); } get categoryId(): string { return this._categoryId; }
Ссылка На Документацию: Посмотрите здесь.
демонстрационный пример: посмотрите на этот plunker.
КАКОЙ ПОДХОД СЛЕДУЕТ ИСПОЛЬЗОВАТЬ?
Если ваш компонент имеет несколько входов, то, если вы используете ngOnChanges (), вы получите все изменения для всех входов сразу в ngOnChanges (). Используя этот подход, вы также можете сравнить текущие и предыдущие значения входных данных, которые изменились, и предпринять соответствующие действия.
однако, если вы хотите что-то сделать, когда изменяется только один вход (и вас не волнуют другие входы), тогда может быть проще использовать задатчик входных свойств. Однако этот подход не обеспечивает встроенный способ сравнения предыдущих и текущих значений измененного ввода (что вы можете сделать легко с помощью метода жизненного цикла ngOnChanges).
EDIT 2017-07-25: ОБНАРУЖЕНИЕ УГЛОВЫХ ИЗМЕНЕНИЙ МОЖЕТ ПО-ПРЕЖНЕМУ НЕ СРАБАТЫВАТЬ ПРИ НЕКОТОРЫХ ОБСТОЯТЕЛЬСТВАХ
обычно обнаружение изменений как для сеттера, так и для ngOnChanges будет срабатывать всякий раз, когда родительский компонент изменяет данные, которые он передает ребенку,при условии, что данные являются примитивным типом данных JS (string, number, boolean). Однако в следующих сценариях он не будет срабатывать, и вы должны принять дополнительные действия, чтобы заставить его работать.
Если вы используете вложенный объект или массив (вместо примитивного типа данных JS) для передачи данных от родителя к потомку, обнаружение изменений (с помощью сеттера или ngchanges) может не сработать, как также упоминалось в ответе пользователя: muetzerich. Для решения посмотреть здесь.
Если вы мутируете данные вне углового контекста (т. е. извне), то угловой не будет знать о изменения. Возможно, Вам придется использовать ChangeDetectorRef или NgZone в вашем компоненте для углового уведомления о внешних изменениях и, таким образом, запуска обнаружения изменений. См.этой.
использовать ngOnChanges()
метод жизненного цикла компонента.
ngOnChanges называется сразу после привязки данных свойств проверено и перед просмотром и содержимым проверяются дети, если по крайней мере один из них изменился.
здесь Docs.
я получаю ошибки в консоли, а также компилятор и IDE при использовании SimpleChanges
введите сигнатуру функции. Чтобы предотвратить ошибки, используйте any
ключевое слово в подписи вместо этого.
ngOnChanges(changes: any) {
console.log(changes.myInput.currentValue);
}
EDIT:
как указал Джон ниже, вы можете использовать SimpleChanges
подпись при использовании скобочной нотации, а не точечной нотации.
ngOnChanges(changes: SimpleChanges) {
console.log(changes['myInput'].currentValue);
}
Я просто хочу добавить, что есть еще один крюк жизненного цикла под названием DoCheck
Это полезно, если @Input
value не является примитивным значением.
у меня есть массив, как Input
Так что это не увольняет OnChanges
событие при изменении содержимого (потому что проверка того, что Angular делает, "проста" и не глубока, поэтому массив по-прежнему является массивом, даже если содержимое массива изменилось).
затем я реализую некоторый пользовательский код проверки, чтобы решить, хочу ли я обновить мой вид с измененным массивом.
вы также можете иметь наблюдаемый, который запускает изменения в Родительском компоненте (CategoryComponent) и делает то, что вы хотите сделать в подписке в дочернем компоненте. (videoListComponent)
service.ts
public categoryChange$ : ReplaySubject<any> = new ReplaySubject(1);
-----------------
CategoryComponent.ts
public onCategoryChange(): void {
service.categoryChange$.next();
}
-----------------
videoListComponent.ts
public ngOnInit(): void {
service.categoryChange$.subscribe(() => {
// do your logic
});
}
в руководстве есть пример:
https://angular.io/guide/component-interaction#intercept-input-property-changes-with-ngonchanges