2016-02-10 11 views
33

Ich habe eine einfache Benutzeroberfläche, die aus zwei Komponenten (Eltern und Kind) bestehen.Angular 2 ngModel in untergeordneten Komponente aktualisiert übergeordneten Komponente Eigenschaft

Was die Benutzeroberfläche tut, ist, dass wenn ich einige Sachen in das Eingabefeld der Child-Komponente eintippe. Der Wert ändert sich mit ngModel.

Die Kindkomponente funktioniert auf diese Weise.

Jetzt habe ich eine Elternkomponente, die ich den gleichen Wert wie Child-Komponente verwenden möchte.

Ich habe die untergeordnete Komponente in die übergeordnete Vorlage eingefügt und die Abhängigkeitsinjektion verwendet, um die sharedVar der untergeordneten Komponente aufzurufen.

// Parent Component 
@Component({ 
    selector: 'parent', 
    template: ` 
     <h1>{{sharedVar}}</h1> 
     <child></child> 
    `, 
    directives: [ChildComponent], 
    providers: [ChildCompnent] 
}) 
export class ParentComponent { 
    sharedVar: string; 
    constructor(child: ChildComponent) { 
     this.sharedVar = child.sharedVar; 
    } 
} 

Das Problem ist, wie ich in das Eingabefeld tippen bin, wird der Wert in <p> ändert sich automatisch, während der Wert in <h1> der Mutterkomponente ändern sich nicht.

+1

Injizieren Sie keine Komponenten, Sie übergeben Werte an untergeordnete Komponenten mit '@ Input' https://angular.io/docs/ts/latest/api/core/Input-var.html, der von der Vorlage erstellten Instanz und die Instanz, die Sie durch Angabe eines Providers erstellen, sind zwei verschiedene Instanzen. – Langley

Antwort

73

Wir können die [(x)] Syntax in der übergeordneten Vorlage verwenden Zwei-Wege-Datenbindung zu erreichen mit dem Kind. Wenn wir eine Output-Eigenschaft mit dem Namen xChange erstellen, aktualisiert Angular automatisch die Parent-Eigenschaft. Wir brauchen ein Ereignis emit(), wenn das Kind jedoch den Wert ändert:

import {Component, EventEmitter, Input, Output} from 'angular2/core' 

@Component({ 
    selector: 'child', 
    template: ` 
     <p>Child sharedVar: {{sharedVar}}</p> 
     <input [ngModel]="sharedVar" (ngModelChange)="change($event)"> 
    ` 
}) 
export class ChildComponent { 
    @Input() sharedVar: string; 
    @Output() sharedVarChange = new EventEmitter(); 
    change(newValue) { 
     console.log('newvalue', newValue) 
     this.sharedVar = newValue; 
     this.sharedVarChange.emit(newValue); 
    } 
} 

@Component({ 
    selector: 'parent', 
    template: ` 
     <div>Parent sharedVarParent: {{sharedVarParent}}</div> 
     <child [(sharedVar)]="sharedVarParent"></child> 
    `, 
    directives: [ChildComponent] 
}) 
export class ParentComponent { 
    sharedVarParent ='hello'; 
    constructor() { console.clear(); } 
} 

Plunker

I sharedVarParent im Parent verwenden nur zeigen, dass die Namen müssen nicht gleich sein in das Elternteil und das Kind.

+5

Jetzt ist das nur reines Gold. Diese Informationen sollten in der offiziellen Dokumentation im Abschnitt "Cookbook/Component Interaction" auf der Website angular.io enthalten sein. – codeepic

+3

Erstaunlich!Die Updates waren jedoch zunächst nicht in meinem Elternteil. Anscheinend ist es sehr wichtig, dass der Var-Name des @Output() -Ereignisses exakt mit dem Eingabe-Var übereinstimmt, aber mit 'Change' dahinter steht. Wird das irgendwo von Angular beschrieben? – deadconversations

+1

@deadconversations, ja, es wird [hier] erwähnt (https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ngModel) - scrollen Sie nach unten zur zweiten grünen Balken-Notiz . –

3

Sie könnten die Ereignis-Emitter-Kommunikation (outputs) von Kind zu Eltern einrichten. Zum Beispiel wie folgt aus:

@Component({ 
    selector: 'child', 
    template: ` 
     <p>Child: {{sharedVar}}</p> 
     <input [(ngModel)]="sharedVar" (ngModelChange)="change()"> 
    ` 
}) 
export class ChildComponent { 
    @Output() onChange = new EventEmitter(); 
    sharedVar: string; 
    change() { 
     this.onChange.emit({value: this.sharedVar}); 
    } 
} 

und die in Stammkomponente:

@Component({ 
    selector: 'parent', 
    template: ` 
     <h1>{{sharedVar}}</h1> 
     <child (onChange)="sharedVar = $event.value"></child> 
    `, 
    directives: [ChildComponent] 
}) 
export class ParentComponent { 
    sharedVar: string; 
    constructor() { 

    } 
} 

Demo:http://plnkr.co/edit/T2KH4nGKPSy6GEvbF1Nb?p=info

+0

Er verwendet bereits die Verknüpfung von @Output mit der Zwei-Wege-Bindung. Er überschreibt einfach seine eigene Komponente mit 'providers: [ChildCompnent]'. Das ist einfacher imo: http://plnkr.co/edit/Qo0dMzDf9HeSGHnwhl2d?p=preview – Langley

+0

@Langley, sehe ich nicht Eltern Eigenschaft 'sharedVar' in Ihrem Plünderer ändern. Ich denke, wir müssen ein Ereignis "emittieren"(), um Änderungen an den Eltern zu erhalten. –

+2

Sie können diesen Ansatz vereinfachen, indem Sie '[(sharedVar)]' in der übergeordneten Vorlage verwenden und dann die Ausgabeeigenschaft 'sharedVarChange' benennen. Siehe meine Antwort für Details, wenn Sie interessiert sind. –