Das Kind wartet in Angular 2 auf das übergeordnete Ereignis


82

In eckigen Dokumenten gibt es ein Thema zum Abhören von Kinderereignissen von Eltern. Das ist gut. Aber mein Zweck ist etwas Umgekehrtes!. In meiner App gibt es eine 'admin.component', die die Layoutansicht der Admin-Seite enthält (Seitenleistenmenü, Taskleiste, Status usw.). In dieser übergeordneten Komponente habe ich das Routersystem zum Ändern der Hauptansicht zwischen anderen Seiten des Administrators konfiguriert. Das Problem besteht darin, dass nach dem Ändern Dinge gespeichert werden. Der Benutzer klickt auf die Schaltfläche Speichern in der Taskleiste (die sich in der admin.component befindet) und die untergeordnete Komponente muss dieses Klickereignis abhören, um Mitarbeiter zu speichern.


2
Klingt so, als ob die beste Vorgehensweise darin besteht, einen Dienst zu verwenden und das Ereignis beobachtbar auszulösen.
zpul

Ihre Frage ist nicht allzu verschieden von dieser: stackoverflow.com/questions/35560860/…
freethebees

@freethebees Vielleicht ist die Lösung dieselbe, aber die Form des Problems ist unterschiedlich und meine Absicht ist es, den besten Ansatz für diese Situation zu finden.
Hamed Hamedi

Wir werden keinen Dienst für ein einzelnes Ereignis einrichten, das an eine untergeordnete Komponente übergeben wird.
Ben Racicot

Antworten:


101

Ich denke, dass dieses Dokument für Sie hilfreich sein könnte:

Tatsächlich könnten Sie ein beobachtbares Objekt nutzen, das der Elternteil seinen Kindern zur Verfügung stellt. So ähnlich:

@Component({
  (...)
  template: `
    <child [parentSubject]="parentSubject"></child>
  `,
  directives: [ ChildComponent ]
})
export class ParentComponent {
  parentSubject:Subject<any> = new Subject();

  notifyChildren() {
    this.parentSubject.next('some value');
  }
}

Die untergeordnete Komponente kann dieses Thema einfach abonnieren:

@Component({
  (...)
})
export class ChildComponent {
  @Input()
  parentSubject:Subject<any>;

  ngOnInit() {
    this.parentSubject.subscribe(event => {
      // called when the notifyChildren method is
      // called in the parent component
    });
  }

  ngOnDestroy() {
    // needed if child gets re-created (eg on some model changes)
    // note that subsequent subscriptions on the same subject will fail
    // so the parent has to re-create parentSubject on changes
    this.parentSubject.unsubscribe();
  }

}

Andernfalls könnten Sie einen gemeinsam genutzten Dienst, der ein solches Thema enthält, auf ähnliche Weise nutzen ...


Der Rückruf in meiner untergeordneten Komponente wird nur ausgeführt, wenn die übergeordnete Komponente den nächsten Wert aus ngInit sendet. Warum ist das so?
cjsimon

5
Gibt es Vorteile bei der Verwendung dieser Methode gegenüber ViewChild?
sunnyiitkgp

Obwohl es professioneller aussieht, konnte ich nach einigen Stunden zum Experimentieren in meiner Situation keine Probleme mit UnsubscribeErrors haben, wenn ich untergeordnete Elemente hinzufügte / entfernte (und mich daher vom Thema abmeldete). Mit TimeBoxing habe ich mich für die viel einfachere Antwort von @StephenPaul entschieden. Wie auch immer, danke für die Antwort und wahrscheinlich bekomme ich die rxjs-Bibliothek gerade nicht gut genug, um sie vollständig zu verstehen und die richtigen (zusätzlichen) Anpassungen an Ihrem Beispiel vorzunehmen, damit es einwandfrei funktioniert.
Bernoulli IT

116

Aus Gründen der Nachwelt dachte ich nur, ich würde die konventionellere Lösung dafür erwähnen : Erhalten Sie einfach einen Verweis auf das ViewChild und rufen Sie dann eine seiner Methoden direkt auf.

@Component({
  selector: 'app-child'
})
export class ChildComponent {

  notifyMe() {
    console.log('Event Fired');
  }
}

@Component({
  selector: 'app-parent',
  template: `<app-child #child></app-child>`
})
export class ParentComponent {

  @ViewChild('child')
  private child: ChildComponent;

  ngOnInit() {
    this.child.notifyMe();
  }
}

3
Es stürzt ab, sobald ich die übergeordnete Komponente geben ... Cannot read property 'notifyMe' of undefined.
freundlicher Benutzer

1
Ging für diese sehr einfache Lösung im Vergleich zu der irgendwie professionelleren Gefühlslösung von @ThierryTemplier (siehe meinen Kommentar dort).
Bernoulli IT

2
@BernoulliIT du machst einen guten Punkt. Ich nehme an, am Ende des Tages erreichen sie ungefähr das Gleiche. Meine Lösung verwendet weniger Code. Seine Lösung bedeutet, dass die übergeordnete Komponente die untergeordnete Komponente nicht injizieren muss, um Nachrichten zu senden. RXJS ist großartig, aber ich sehe oft eine Überbeanspruchung in Angular-Projekten. Die Leute denken, es ist diese "Silberkugel" oder so. Es kann die Dinge tatsächlich viel komplizierter machen, als sie sein müssen. Schauen Sie sich seinen Kommentar in seiner ngOnDestroy()Methode an. Das ist mir viel zu dunkel. Das ist nur ein Fehler, der IMHO darauf wartet, passiert zu werden.
Stephen Paul

1
"Sehen Sie sich seinen Kommentar in seiner ngOnDestroy () -Methode an." Ich denke, genau daran habe ich "gelitten", als ich diesen Ansatz ausprobiert habe. Dann blieb ich stecken und hatte nicht so viel Zeit, um weiter nachzuforschen (für ein kommerzielles Projekt, an dem ich arbeite). Obwohl es mein berufliches Herz ein bisschen "verletzt" hat;)
Bernoulli IT

1
Vielen Dank an @StephenPaul, für mich war Parent Views eine Viewchild- Methode gut, aber Ihre Antwort hat mir geholfen, mein Schicksal zu erreichen!
MKJ

14

Ein nackterer Ansatz könnte hier möglich sein, wenn ich die Frage richtig verstehe. Annahmen --

  • OP verfügt über eine Schaltfläche zum Speichern in der übergeordneten Komponente
  • Die Daten, die gespeichert werden müssen, befinden sich in den untergeordneten Komponenten
  • Auf alle anderen Daten, die die untergeordnete Komponente möglicherweise benötigt, kann über Dienste zugegriffen werden

In der übergeordneten Komponente

<button type="button" (click)="prop1=!prop1">Save Button</button>
<app-child-component [setProp]='prop1'></app-child-component>

Und im Kind ..

prop1:boolean;
  @Input()
  set setProp(p: boolean) {
    // -- perform save function here
}

Dadurch wird einfach der Klick auf die Schaltfläche an die untergeordnete Komponente gesendet. Von dort aus kann die untergeordnete Komponente die Daten unabhängig speichern.

BEARBEITEN: Wenn Daten aus der übergeordneten Vorlage zusammen mit dem Klicken auf die Schaltfläche übergeben werden müssen, ist dies auch mit diesem Ansatz möglich. Lassen Sie mich wissen, ob dies der Fall ist, und ich werde die Codebeispiele aktualisieren.


0

Für diejenigen, die bekommen Cannot read property 'notifyMe' of undefined

Versuchen Sie, die Methode in ngAfterViewInit()intead von aufzurufenngOnInit()

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.