2016-03-27 16 views
16

Prima ho creato una classe User:Come utilizzare il collegamento dati bidirezionale tra i componenti in Angular 2?

export class User { 
    name: string; 
    email: string; 
} 

Poi ho ottenuto il mio CoreComponent che utilizza il FormInputComponent così come la creazione di un public user dalla classe User:

import {Component} from 'angular2/core'; 
import {FormInputComponent} from '../form-controls/form-input/form-input.component'; 
import {User} from '../core/user'; 

@Component({ 
    selector: 'core-app', 
    templateUrl: './app/assets/scripts/modules/core/core.component.html', 
    styleUrls: ['./app/assets/scripts/modules/core/core.component.css'], 
    directives: [FormInputComponent] 
}) 

export class CoreComponent { 
    public user: User = { 
    name: '', 
    email: '' 
    } 
} 

Poi ho' abbiamo creato un componente di input, che è un componente di input riutilizzabile che assumerà un valore di modello come input e quando vengono apportate modifiche esporta il nuovo valore in modo che CoreComponent possa aggiornare il modello con il nuovo valore:

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

@Component({ 
    selector: 'form-input', 
    templateUrl: './app/assets/scripts/modules/form-controls/form-input/form-input.component.html', 
    styleUrls: ['./app/assets/scripts/modules/form-controls/form-input/form-input.component.css'], 
    inputs: [ 
    'model', 
    'type', 
    'alt', 
    'placeholder', 
    'name', 
    'label' 
    ] 
}) 

export class FormInputComponent implements DoCheck { 
    @Input() model: string; 
    @Output() modelExport: EventEmitter = new EventEmitter(); 

    ngDoCheck() { 
    this.modelExport.next(this.model); 
    } 
} 

modello s' The CoreComponent utilizza due FormInputComponent s e passa user.name e user.email come ingresso per loro:

<form-input [model]="user.name" type="text" name="test" placeholder="This is a test" alt="A test input" label="Name"></form-input> 
<form-input [model]="user.email" type="email" name="test" placeholder="This is a test" alt="A test input" label="Email"></form-input> 
<pre>{{user.name}}</pre> 

Il modello FormInputComponent:

<div> 
    <label attr.for="{{name}}">{{label}}</label> 
    <input [(ngModel)]="model" type="{{type}}" placeholder="{{placeholder}}" alt="{{alt}}" id="{{name}}"> 
</div> 
<pre>{{model}}</pre> 

Ora il problema è che Posso vedere solo le modifiche dall'elemento pre che si trova all'interno dello FormInputComponent modello, ma l'elemento genitore, , pre rimane invariato.

Ho guardato allo this question che si trova nel campo da baseball di ciò che voglio ottenere ma non abbastanza da quando usare un servizio per restituire un valore nella gerarchia sembra eccessivo e un po 'caotico se si dispone di più FormInputComponent s sullo stesso pagina.

Quindi la mia domanda è semplice, come posso passare un modello per FormInputComponent e lasciandolo restituire un nuovo valore ogni volta che il valore cambia in modo che il public user in CoreComponent cambia automaticamente?

risposta

24

Per poter utilizzare vincolante breve quando si utilizza il componente è necessario Leggimi la vostra proprietà di output per modelChange due vie:

export class FormInputComponent implements DoCheck { 
    @Input() model: string; 
    @Output() modelChange: EventEmitter = new EventEmitter(); 

    ngDoCheck() { 
    this.modelChange.next(this.model); 
    } 
} 

e usarlo in questo modo:

<form-input [(model)]="user.name" type="text" name="test" placeholder="This is a test" alt="A test input" label="Name"></form-input> 
<form-input [(model)]="user.email" type="email" name="test" placeholder="This is a test" alt="A test input" label="Email"></form-input> 
<pre>{{user.name}}</pre> 
+0

Quindi la mia soluzione non funzionava perché non avevo() in [modello]? Sai anche un modo migliore di dire quando l'input cambia rispetto all'utilizzo di ngDoCheck? Ho controllato ngOnChanges ma sembra funzionare solo se è vincolante per gli oggetti o qualcosa del genere? – Chrillewoodz

+1

E anche il nome del tuo input ;-) Puoi sfruttare l'evento ngModelUpdate sul tuo input:

+0

Cool Funziona! Sembra che ngDoCheck sia orribile per le prestazioni, perché stavo soffrendo per il fatto che il server si disconnetteva tutto il tempo anche solo con due ingressi. Ma una volta rimosso tutto scorre liscio, strano. Grazie mille per il tuo aiuto! – Chrillewoodz

6

Questo è stato troppo da aggiungere come commento alla risposta di Thierry ...

Utilizzare emit() anziché next() (che è deprecato) e chiamare solo emit(newValue) quando cambia il valore di model. Molto probabilmente si desidera qualcosa di simile nel modello FormInputComponent:

<input [ngModel]="model" (ngModelChange)="onChanges($event)"> 

Poi nella logica FormInputComponent:

onChanges(newValue) { 
    this.model = newValue; 
    this.changeModel.emit(newValue); 
} 
+0

Dove hai letto che next() è deprecato? Non l'ho visto da nessuna parte, e i documenti sono incompleti quindi non posso davvero dire cosa c'è ancora e cosa no. – Chrillewoodz

+0

@Chrillewoodz, qualcun altro su SO lo ha menzionato, ma è anche nel codice sorgente: https://github.com/angular/angular/blob/2.0.0-beta.12/modules/angular2/src/facade/ async.ts # L116 –

+0

Va bene, va bene. Poi lo aggiornerò :) – Chrillewoodz

17

In aggiunta: Utilizzo ngDoCheck per emettere le modifiche del modello drasticamente influenzare le prestazioni come nuovo valore viene emesso ad ogni ciclo di controllo, non importa se è stato modificato o meno. E questo è molto spesso! (Prova un console.log!)

Quindi quello che mi piace fare per ottenere una comodità paragonabile, ma senza gli effetti collaterali, è qualcosa di simile:

private currentSelectedItem: MachineItem; 
@Output() selectedItemChange: EventEmitter<MachineItem> = new EventEmitter<MachineItem>(); 

@Input() set selectedItem(machineItem: MachineItem) { 
    this.currentSelectedItem = machineItem; 
    this.selectedItemChange.emit(machineItem); 
} 

get selectedItem(): MachineItem { 
    return this.currentSelectedItem; 
} 

e usarlo come

<admin-item-list [(selectedItem)]="selectedItem"></admin-item-list> 

È possibile anche emettere il nuovo valore in cui è effettivamente cambiato. Ma trovo molto conveniente fare questo gloabaly in un metodo setter e non devo preoccuparmi quando lo lego direttamente a mio avviso.

+0

Questo cambiamento viene catturato dal rilevamento delle modifiche di Angular? – Anshul

+3

E come è noto l'elemento contenitore per l'ascolto su selectedItemChange? È una convenzione in Angular? Che puoi aggiungere "Cambia" alla fine del nome della proprietà e mapperà automaticamente la proprietà a quell'output? – Anshul

+3

Sì, questa è la convenzione angolare2 ufficiale, documentata e stabile. È così che funziona il binding bidirezionale angolare2. Puoi leggere di più qui: https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ngModel sotto "Inside [(ngModel)]" –

Problemi correlati