otro - pasar datos entre componentes angular 5
¿Cómo comparto datos entre componentes en Angular 2? (6)
En Angular 1.xx simplemente solicita el mismo servicio y termina con la misma instancia, lo que permite compartir los datos en el servicio.
Ahora en Angular 2 tengo un componente que hace referencia a mi servicio. Puedo leer y modificar los datos en el servicio, lo cual es bueno. Cuando intento inyectar el mismo servicio en otro componente, parece que obtengo una nueva instancia.
¿Qué estoy haciendo mal? ¿Es el patrón en sí lo que está mal (usando un servicio para compartir datos) o necesito marcar el servicio como un singleton (dentro de una instancia de la aplicación) o algo así?
Estoy en
2.0.0-alpha.27/
cierto
appInjector
un servicio a través de
appInjector
(editar: ahora
providers
) en la anotación
@Component
y luego
@Component
una referencia en el constructor.
Funciona localmente en el componente, pero no en todos los componentes (no comparten la misma instancia de servicio) como pensé que lo harían.
ACTUALIZACIÓN
: A partir de Angular 2.0.0 ahora tenemos @ngModule donde definiría el servicio bajo la propiedad de
providers
en dicho
@ngModule
.
Eso asegurará que la misma instancia de ese servicio se pase a cada componente, servicio, etc. en ese módulo.
https://angular.io/docs/ts/latest/guide/ngmodule.html#providers
Debe usar entradas y salidas de un decorador @Component. Aquí está el ejemplo más básico de usar ambos;
import { bootstrap } from ''angular2/platform/browser'';
import { Component, EventEmitter } from ''angular2/core'';
import { NgFor } from ''angular2/common'';
@Component({
selector: ''sub-component'',
inputs: [''items''],
outputs: [''onItemSelected''],
directives: [NgFor],
template: `
<div class="item" *ngFor="#item of items; #i = index">
<span>{{ item }}</span>
<button type="button" (click)="select(i)">Select</button>
</div>
`
})
class SubComponent {
onItemSelected: EventEmitter<string>;
items: string[];
constructor() {
this.onItemSelected = new EventEmitter();
}
select(i) {
this.onItemSelected.emit(this.items[i]);
}
}
@Component({
selector: ''app'',
directives: [SubComponent],
template: `
<div>
<sub-component [items]="items" (onItemSelected)="itemSelected($event)">
</sub-component>
</div>
`
})
class App {
items: string[];
constructor() {
this.items = [''item1'', ''item2'', ''item3''];
}
itemSelected(item: string): void {
console.log(''Selected item:'', item);
}
}
bootstrap(App);
Depende, si hay un caso simple
a) A -> B -> C A tiene dos hijos B y C y si desea compartir datos entre A y B o A y C, entonces use (entrada / salida)
Si desea compartir entre B y C, también puede usar (entrada / salida) pero se sugiere usar el Servicio.
b) Si el árbol es grande y complejo. (si hay tantos niveles de conexiones entre padres e hijos). Y en este caso, si desea compartir datos, sugeriría ngrx
Implementa la arquitectura de flujo que crea una tienda del lado del cliente a la que cualquier componente puede suscribirse y actualizarse sin crear ninguna condición de carrera.
El comentario de @maufarinelli merece su propia respuesta porque hasta que lo vi, todavía estaba golpeando mi cabeza contra la pared con este problema, incluso con la respuesta de @Alexander Ermolov.
El problema es que cuando agrega
providers
a su
component
:
@Component({
selector: ''my-selector'',
providers: [MyService],
template: `<div>stuff</div>`
})
Esto hace que se inyecte una nueva instancia de su servicio ... en lugar de ser un singleton .
¡
providers: [MyService]
todas las instancias de sus
providers: [MyService]
en su aplicación, excepto en el
module
, y funcionará!
En la plantilla del componente principal:
<hero-child [hero]="hero">
</hero-child>
En componente infantil:
@Input() hero: Hero;
Fuente: https://angular.io/docs/ts/latest/cookbook/component-communication.html
Hay muchas maneras. Este es un ejemplo que utiliza la propagación entre elementos primarios y secundarios. Esto es muy eficiente.
Envié un ejemplo que permite ver el uso de dos formas de enlace de datos dentro de dos formularios. Si alguien puede proporcionar una muestra de plunkr, esto sería muy bueno ;-)
Puede buscar otra forma utilizando un proveedor de servicios. También puede ver este video como referencia: ( Compartir datos entre componentes en angular )
mymodel.ts (datos para compartir)
// Some data we want to share against multiple components ...
export class mymodel {
public data1: number;
public data2: number;
constructor(
) {
this.data1 = 8;
this.data2 = 45;
}
}
Recuerde: debe haber un padre que comparta "mymodel" con los componentes secundarios.
Componente principal
import { Component, OnInit } from ''@angular/core'';
import { mymodel } from ''./mymodel'';
@Component({
selector: ''app-view'',
template: ''<!-- [model]="model" indicates you share model to the child component -->
<app-mychild [model]="model" >
</app-mychild>''
<!-- I add another form component in my view,
you will see two ways databinding is working :-) -->
<app-mychild [model]="model" >
</app-mychild>'',
})
export class MainComponent implements OnInit {
public model: mymodel;
constructor() {
this.model = new mymodel();
}
ngOnInit() {
}
}
Componente hijo, mychild.component.ts
import { Component, OnInit,Input } from ''@angular/core'';
import { FormsModule } from ''@angular/forms''; // <-- NgModel lives here
import { mymodel } from ''./mymodel'';
@Component({
selector: ''app-mychild'',
template: ''
<form #myForm="ngForm">
<label>data1</label>
<input type="number" class="form-control" required id="data1 [(ngModel)]="model.data1" name="data1">
<label>val {{model.data1}}</label>
label>data2</label>
<input id="data2" class="form-control" required [(ngModel)]="model.data2" name="data2" #data2="ngModel">
<div [hidden]="data2.valid || data2.pristine"
class="alert alert-danger">
data2 is required
</div>
<label>val2 {{model.data2}}</label>
</form>
'',
})
export class MychildComponent implements OnInit {
@Input() model: mymodel ; // Here keywork @Input() is very important it indicates that model is an input for child component
constructor() {
}
ngOnInit() {
}
}
Nota: en algunos casos raros, puede tener un error cuando se analiza el código HTML, porque el modelo no está "listo" para usar en la inicialización de la página. En este caso, prefija el código HTML con una condición ngIf:
<div *ngIf="model"> {{model.data1}} </div>
Un servicio singleton es una buena solución.
Otra forma:
data/events bindings
.
Aquí hay un ejemplo de ambos:
class BazService{
n: number = 0;
inc(){
this.n++;
}
}
@Component({
selector: ''foo''
})
@View({
template: `<button (click)="foobaz.inc()">Foo {{ foobaz.n }}</button>`
})
class FooComponent{
constructor(foobaz: BazService){
this.foobaz = foobaz;
}
}
@Component({
selector: ''bar'',
properties: [''prop'']
})
@View({
template: `<button (click)="barbaz.inc()">Bar {{ barbaz.n }}, Foo {{ prop.foobaz.n }}</button>`
})
class BarComponent{
constructor(barbaz: BazService){
this.barbaz = barbaz;
}
}
@Component({
selector: ''app'',
viewInjector: [BazService]
})
@View({
template: `
<foo #f></foo>
<bar [prop]="f"></bar>
`,
directives: [FooComponent, BarComponent]
})
class AppComponent{}
bootstrap(AppComponent);