wake-up-neo.com

Wie kann ich feststellen, wenn sich ein @Input () - Wert in Angular ändert?

Ich habe eine übergeordnete Komponente ( CategoryComponent ), eine untergeordnete Komponente ( videoListComponent ) und einen ApiService.

Das meiste davon funktioniert gut, d. H. Jede Komponente kann auf die Json-API zugreifen und ihre relevanten Daten über Observables abrufen.

Derzeit erhält die Videolistenkomponente nur alle Videos. Ich möchte dies nach Videos in einer bestimmten Kategorie filtern. Dies wurde erreicht, indem die categoryId über @Input() an das Kind übergeben wurde.

CategoryComponent.html

<video-list *ngIf="category" [categoryId]="category.id"></video-list>

Dies funktioniert und wenn sich die übergeordnete CategoryComponent-Kategorie ändert, wird der categoryId-Wert über @Input() durchgereicht. Ich muss dies jedoch in VideoListComponent feststellen und das Videos-Array erneut über APIService (mit der neuen categoryId) anfordern.

In AngularJS hätte ich einen $watch für die Variable gemacht. Wie gehe ich am besten damit um?

261
Jon Catmull

Eigentlich gibt es zwei Möglichkeiten, um zu erkennen und darauf zu reagieren, wenn sich eine Eingabe in der untergeordneten Komponente in angle2 + ändert);

  1. Sie können die ngOnChanges () - Lebenszyklusmethode verwenden, wie auch in älteren Antworten erwähnt:
    @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

    }

Dokumentationslinks: ngOnChanges,SimpleChanges,SimpleChange
Demo-Beispiel: Schauen Sie sich diesen Plunker an

  1. Alternativ können Sie auch einen Eingabeeigenschaften-Setter wie folgt verwenden:
    private _categoryId: string;

    @Input() set categoryId(value: string) {

       this._categoryId = value;
       this.doSomething(this._categoryId);

    }

    get categoryId(): string {

        return this._categoryId;

    }

Dokumentationslink: Siehe hier

Demo-Beispiel: Schauen Sie sich diesen Plunker an.

Welchen Ansatz sollten Sie verwenden?

Wenn Ihre Komponente über mehrere Eingaben verfügt, erhalten Sie bei Verwendung von ngOnChanges () alle Änderungen für alle Eingaben gleichzeitig in ngOnChanges (). Mit diesem Ansatz können Sie auch aktuelle und frühere Werte der geänderten Eingabe vergleichen und entsprechend handeln.

Wenn Sie jedoch etwas tun möchten, wenn sich nur eine bestimmte Eingabe ändert (und Sie sich nicht für die anderen Eingaben interessieren), ist es möglicherweise einfacher, einen Eingabeeigenschaften-Setter zu verwenden. Dieser Ansatz bietet jedoch keine integrierte Möglichkeit, vorherige und aktuelle Werte der geänderten Eingabe zu vergleichen (was mit der Lebenszyklusmethode ngOnChanges problemlos möglich ist).

EDIT 2017-07-25: ANGULAR CHANGE DETECTION KANN NOCH NICHT FEUER UNTER EINIGEN UMSTÄNDEN BRINGEN}

Normalerweise wird die Änderungserkennung sowohl für Setter als auch für ngOnChanges ausgelöst, wenn die übergeordnete Komponente die an das untergeordnete Objekt übergebenen Daten ändert, sofern es sich bei den Daten um einen primären JS-Datentyp (String, Number, Boolean)In den folgenden Szenarien wird es jedoch nicht ausgelöst, und Sie müssen zusätzliche Maßnahmen ergreifen, damit es funktioniert.

  1. Wenn Sie ein verschachteltes Objekt oder ein verschachteltes Objekt (anstelle eines primären JS-Datentyps) verwenden, um Daten von Parent an Child zu übergeben, wird die Änderungserkennung (mithilfe von Setter oder ngchanges) möglicherweise nicht ausgelöst, wie auch in der Antwort des Benutzers Muetzerich erwähnt. Für Lösungen siehe hier

  2. Wenn Sie Daten außerhalb des Winkelkontexts (d. H. Extern) mutieren, werden die Änderungen von winkle nicht erkannt. Möglicherweise müssen Sie in Ihrer Komponente ChangeDetectorRef oder NgZone verwenden, um Winkeländerungen auf externe Änderungen aufmerksam zu machen und dadurch die Änderungserkennung auszulösen. Siehe this .

377
Alan C. S.

Verwenden Sie in Ihrer Komponente die Lebenszyklusmethode ngOnChanges().

ngOnChanges wird direkt nach den datengebundenen Eigenschaften aufgerufen überprüft und vor dem Anzeigen von Inhalten und untergeordneten Elementen werden mindestens einer von ihnen hat sich verändert.

Hier sind die Docs .

89
muetzerich

Beim Verwenden des SimpleChanges-Typs in der Funktionssignatur wurden Fehler in der Konsole sowie im Compiler und IDE angezeigt. Um die Fehler zu vermeiden, verwenden Sie stattdessen das Schlüsselwort any in der Signatur.

ngOnChanges(changes: any) {
    console.log(changes.myInput.currentValue);
}

BEARBEITEN:

Wie Jon weiter unten erläutert hat, können Sie die SimpleChanges-Signatur verwenden, wenn Sie Klammer-Notation anstelle von Punktnotation verwenden.

ngOnChanges(changes: SimpleChanges) {
    console.log(changes['myInput'].currentValue);
}
25
Darcy

Am sichersten ist es, wenn Sie stattdessen einen gemeinsam genutzten Dienst verwenden eines @Input-Parameters . Außerdem erkennt @Input-Parameter keine Änderungen in einem komplexen verschachtelten Objekttyp.

Ein einfaches Beispielservice lautet wie folgt:

Service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class SyncService {

    private thread_id = new Subject<number>();
    thread_id$ = this.thread_id.asObservable();

    set_thread_id(thread_id: number) {
        this.thread_id.next(thread_id);
    }

}

Component.ts

export class ConsumerComponent implements OnInit {

  constructor(
    public sync: SyncService
  ) {
     this.sync.thread_id$.subscribe(thread_id => {
          **Process Value Updates Here**
      }
    }

  selectChat(thread_id: number) {  <--- How to update values
    this.sync.set_thread_id(thread_id);
  }
}

Sie können eine ähnliche Implementierung in anderen Komponenten verwenden, und für alle Ihre Komponenten gelten dieselben gemeinsamen Werte.

6
Sanket Berde

Sie können auch eine Beobachtungsmöglichkeit haben, die bei Änderungen in der übergeordneten Komponente (CategoryComponent) ausgelöst wird und das tut, was Sie in der Subscription der untergeordneten Komponente tun möchten. (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
});
}
1
Josf

Ich möchte nur hinzufügen, dass es einen weiteren Lifecycle-Hook namens DoCheck gibt, der nützlich ist, wenn der @Input-Wert kein primitiver Wert ist.

Ich habe ein Array als Input, so dass das OnChanges-Ereignis nicht ausgelöst wird, wenn sich der Inhalt ändert (da Angular 'einfach' und nicht tief überprüft wird, sodass das Array immer noch ein Array ist, obwohl der Inhalt des Arrays geändert wurde ).

Anschließend implementiere ich benutzerdefinierten Überprüfungscode, um zu entscheiden, ob ich meine Ansicht mit dem geänderten Array aktualisieren möchte. 

1
Stevo
  @Input()
  public set categoryId(categoryId: number) {
      console.log(categoryId)
  }

bitte versuchen Sie es mit dieser Methode. Hoffe das hilft

0
Akshay Rajput
0
Emmanuel John

Hier wird ngOnChanges immer dann ausgelöst, wenn sich Ihre Eingabeeigenschaft ändert:

ngOnChanges(changes: SimpleChanges): void {
 console.log(changes.categoryId.currentValue)
}
0
Chirag

Wenn Sie die ngOnChange-Methode implementOn onChange () nicht verwenden möchten, können Sie Änderungen an einem bestimmten Element auch durch das valueChanges-Ereignis , ETC abonnieren.

 myForm= new FormGroup({
first: new FormControl()   

});

this.myForm.valueChanges.subscribe(formValue => {
  this.changeDetector.markForCheck();
});

das markForCheck () wurde geschrieben, weil es in dieser deklariert wurde:

  changeDetection: ChangeDetectionStrategy.OnPush
0
user1012506