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

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

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

  2. Если вы мутируете данные вне углового контекста( т. е. внешне), то 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
});
}