Как определить, когда значение @Input() изменяется в угловом?
у меня есть родительский компонент (CategoryComponent), дочернего компонента (videoListComponent) и ApiService.
у меня большая часть этого работает нормально, т. е. каждый компонент может получить доступ к api json и получить свои соответствующие данные через наблюдаемые.
В настоящее время компонент списка видео просто получает все видео, я хотел бы отфильтровать это только видео в определенной категории, я достиг этого, передав categoryId ребенку через @Input()
.
CategoryComponent.HTML-код
<video-list *ngIf="category" [categoryId]="category.id"></video-list>
это работает, и когда родительская категория CategoryComponent category изменяется, то значение 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кроме того, вы также можете использовать input property 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: ОБНАРУЖЕНИЕ УГЛОВЫХ ИЗМЕНЕНИЙ МОЖЕТ ВСЕ ЕЩЕ НЕ СРАБАТЫВАТЬ ПРИ НЕКОТОРЫХ ОБСТОЯТЕЛЬСТВАХ
обычно обнаружение изменений как для setter, так и для ngOnChanges срабатывает всякий раз, когда родительский компонент изменяет данные, которые он передает дочернему,при условии, что данные являются примитивным типом данных JS (string, number, boolean). Однако в следующих сценариях он не будет срабатывать, и вам придется взять дополнительные действия для того, чтобы заставить его работать.
Если вы используете вложенный объект или массив (вместо примитивного типа данных JS) для передачи данных от родителя к потомку, обнаружение изменений (с помощью setter или ngchanges) может не сработать, как также указано в ответе пользователя: muetzerich. За решениями ищите здесь.
Если вы мутируете данные вне углового контекста( т. е. внешне), то angular не будет знать изменения. Возможно, Вам придется использовать ChangeDetectorRef или NgZone в вашем компоненте для того, чтобы сделать angular осведомленным о внешних изменениях и тем самым инициировать обнаружение изменений. См.этой.
использовать
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
значение не является примитивным значением.у меня есть массив, как
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