Как определить, когда значение @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+ :

  1. можно использовать метод жизненного цикла 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

  2. кроме того, вы также можете использовать входное свойство 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). Однако в следующих сценариях он не будет срабатывать, и вы должны принять дополнительные действия, чтобы заставить его работать.

  1. Если вы используете вложенный объект или массив (вместо примитивного типа данных JS) для передачи данных от родителя к потомку, обнаружение изменений (с помощью сеттера или ngchanges) может не сработать, как также упоминалось в ответе пользователя: muetzerich. Для решения посмотреть здесь.

  2. Если вы мутируете данные вне углового контекста (т. е. извне), то угловой не будет знать о изменения. Возможно, Вам придется использовать 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);
}

самая безопасная ставка-пойти с общим сервис of a


Я просто хочу добавить, что есть еще один крюк жизненного цикла под названием 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
});
}