2016-10-16 1 views
7

Ich lerne Angular2, nach der Arbeit mit Angular1 für ein paar Jahre. Ich erstelle eine Kreditkartenform-Komponente, mit dem Hauptziel, ein paar Schlüsselkonzepte in Angular2 zu lernen. Die Komponente sollte alle Formatierungen verarbeiten und ein Stripe-Token über einen Rückruf zurückgeben. Ich erkannte, dass ich Callbacks auf zwei Arten bearbeiten kann.Angular2 warum @Output über @Input für Rückrufe verwenden

einen @Output Parameter Mit

In meiner Komponente I eine Ausgangsgröße zu definieren und es wie in diesem Beispiel verwenden:

export class CreditCardForm{ 
    .... 
    @Output() callback = new EventEmitter(); 
    .... 

    doCallback(){ 
     this.callback.emit({data: 123}); 
    } 
} 

// Parent view 
<credit-card-form (callback)="creditCardCallback($event)"></credit-card-form> 

Mit einer @Input Variable

jedoch , Könnte ich die Callback-Methode (creditCardCallback, die in der übergeordneten Vorlage verwendet wird) einfach an eine Eingabevariable übergeben, beispielsweise:

export class CreditCardForm{ 
    .... 
    @Input() callback; 
    .... 

    doCallback(){ 
     this.callback({data: 123}); 
    } 
} 

// Parent view 
<credit-card-form [callback]="creditCardCallback"></credit-card-form> 

Die Frage

Warum sollte ich @Output über @Input verwenden? Was erreiche ich mit @Output Variablen statt? Soweit ich sehen kann, fügt dies nur einen Overhead hinzu, indem man die Klasse EventEmitter nutzt.

Antwort

7

Es gibt immer mehr als eine Möglichkeit, die Katze zu häuten. Doch meiner Meinung nach, hat @Output mit folgenden Vorteilen:

  • Lesbarkeit des Codes: Es ist einfacher, den Datenfluss zu wissen, ob den empfohlene Stil verwenden.

  • De-Kopplung: Zum Beispiel für die normale @Output Ereignis in Ihrem ParentComponent, können Sie mehr Flexibilität, um die geschickte Falle Umgang haben:

  • Last but not least - es ermöglicht Banane in die Box Syntax: Sagen Sie in Ihrem ChildComponent Sie haben:

@Input() creditCardValue: string; @Output() creditCardValueChange: EventEmitter<string>;

Dann können Sie Zwei-Wege leicht in Ihrer ParentComponent Bindung haben:

<credit-card-form [(creditCardValue)]="creditCardVal"></credit-card-form> 
+0

Vielen Dank für eine tolle Antwort! Dies überzeugt mich, '@ Output' für Callbacks zu verwenden. Deine Antwort hat mir auch gelehrt, dass es einen Satz wie "Banane in der Box-Syntax" gibt, der beim Googlen zu ein paar lustigen Bildern führt :) –

+0

Ich nehme auch an, dass du mit @ Output die Message Coupling * verwendest im Gegensatz zu * Externe Kopplung * mit '@ Input'. Wenn also der @ @ Input-Parameter im Child nicht definiert ist (hat kein Elternteil?), Dann müssen Sie sich keine Sorgen über 'this.callback && this.callback.call (...)' oder machen 'noOp' Methoden. Aber ich kann ** only ** immer '' Output' 'für Event-Emissionen sehen - * aber ich denke sein schlechtes Design, um deine Event-Typen auf der Komponentenskala im Gegensatz zur App-Skala zu definieren; Es wird Entropie für Ihre App und ihre Ingenieure *. – Cody

+0

Danke Harry! Nur erstaunt, weil ich genau danach suchte. Mein kleines Problem ist: Wie man von hier zu deinem netteren Stil wechselt? gtamborero

-1

Imho, @Output ist ein riesig Designfehler, da Sie nicht auf das Ergebnis reagieren kann, oder die Handhabung davon. Das erste Beispiel für diesen Fehler ist der Klick auf eine Schaltfläche. Wenn Sie darauf klicken, sollte die Schaltfläche in 99% der Fälle deaktiviert werden, wenn die Aktion ausgeführt wird. Sobald die Aktion abgeschlossen ist, sollte die Schaltfläche erneut aktiviert werden. Dies möchten Sie im Element selbst und nicht im übergeordneten Element behandeln. Mit @Output können Sie dies nicht tun. Mit einer Aktionsfunktion wie @Input können Sie dies tun! Und wenn Ihre Aktionsfunktion Observable oder Promise zurückgibt, können Sie leicht darauf warten. Das Erstellen einer benutzerdefinierten Anweisung, die diese Deaktivierung behandelt, ist einfach, und Sie können [klick] überall verwenden und es wird sich so verhalten.

EDIT: Ich sage nicht, @Output nicht, dass es Anwendungen hat, aber nicht für Aktionen müssen Sie auf etc warten .... Benennen @Input gut ist, verdeutlicht auch den Fluss, wie onDelete etc ...

+0

Ich bin kein Fan der Semantik und persönlich bevorzuge React-Style-Callbacks, aber um speziell auf Ihre Bedenken zu reagieren, gibt es keinen Grund, dass Ihr Source-Event den Emitter direkt referenzieren muss. Sehen Sie sich das Dokumentationsbeispiel hier an: https://angular.io/guide/component-interaction#parent-listens-for-child-event. Die untergeordnete Komponente bindet ein Klickereignis an eine Handlerfunktion, die lokal für das Kind ist. Das Kind wiederum ruft auf dem Sender "emit" auf. Dies wäre sicherlich ein guter Ort, um jede Art von Validierung hinzuzufügen, die Sie sich vorstellen können, um die Ereignisausbreitung kurzzuschließen. – FLGMwt

+0

Ja, stimmt, aber Sie können das Ergebnis der Funktion nicht kontrollieren. Ich injiziere immer Aktionen, die Funktionen in einer Komponente sind, so dass die Komponente sie ausführen kann, aber nicht wissen muss, was genau getan wird. Solche Aktionen ergeben ein Observable, weil eine asynchrone Aktion ausgeführt werden kann. Wir brauchen also eine Möglichkeit, die Schaltfläche usw. auf der Grundlage des Status der Aktion zu deaktivieren, und dies ist mit Ausgabe nicht möglich. Mit Output müssen Sie immer vars auf Ihrer Komponente haben, um es zu tun, mit Input und [click] können Sie dies in einer Direktive haben, um es für Sie zu handhaben. –