How to exchange data between components in Angular 2?

In Angular 1.xx, you simply request the same service, and you end up with the same instance, which allows you to share data in the service.

Now in Angular 2, I have a component that has a link to my service. I can read and modify data in the service, which is good. When I try to introduce the same service into another component, it seems that I am getting a new instance.

What am I doing wrong? Is this template incorrect (using the service to exchange data) or do I need to mark the service as a singleton (in one application instance) or something else?

I am on 2.0.0-alpha.27/ btw

I insert the service through appInjector (edit: now providers ) into the @Component annotation, and then save the link in the constructor. It works locally in the component - only not through the components (they do not use the same instance of the service), as I thought they would be.

UPDATE : Starting with Angular 2.0.0, we now have @ngModule, where you define a service under the providers property in the specified @ngModule . This will ensure the transfer of the same instance of this service to each component, service, etc. In this module. https://angular.io/docs/ts/latest/guide/ngmodule.html#providers

+74
angular typescript
Jun 24 '15 at 12:41
source share
6 answers

Singleton service is a good solution. Another way is data/events bindings .

Here is an example of both:

 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); 

Watch live

+56
Jun 24 '15 at 21:14
source share

The @maufarinelli comment deserves an answer of its own because, until I saw it, I was still punching my head against the wall with this problem, even with @Alexander Ermolov's answer.

The problem is that when adding providers to your component :

 @Component({ selector: 'my-selector', providers: [MyService], template: `<div>stuff</div>` }) 

This leads to the introduction of a new instance of your service ... and not to singleton .

Therefore, delete all instances of your providers: [MyService] in the application, except in the module , and it will work!

+43
Oct 22 '16 at 10:54 on
source share

You must use the inputs and outputs of the @Component decorator. Here is the simplest example of using both:

 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); 
+9
Dec 26 '15 at 2:38
source share

In the parent component template:

 <hero-child [hero]="hero"> </hero-child> 

In the child component:

 @Input() hero: Hero; 

Source: https://angular.io/docs/ts/latest/cookbook/component-communication.html

+6
Mar 25 '17 at 23:56 on
source share

There are many ways. This example uses distribution between parent and child elements. It is very effective.

I presented an example that allows you to view the use of two methods of data binding in two forms. If someone can provide a plunkr sample, that would be very good ;-)

You can search for another way using your service provider. You can watch this video for reference too: ( Exchange of data between components in Angular )

mymodel.ts (data for exchange)

 // 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; } } 

Remember: there must be a parent who shares "mymodel" with the child components.

Parent component

 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() { } } 

Child component, 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() { } } 

Note. In some rare cases, an error may occur while parsing the HTML code, because the model is not "ready" for use in page initialization. In this case, add the ngIf condition to the HTML code:

 <div *ngIf="model"> {{model.data1}} </div> 
+2
Jul 24 '17 at 7:26
source share

It depends if there is a simple case.

a) A โ†’ B โ†’ CA has two children B and C, and if you want to exchange data between A and B or and C, use (input / output)

If you want to share between B and C, then you can also use (input / output), but it is recommended to use Service.

b) If the tree is large and complex, like this, for example, And in this case, if you want to share data, then I would suggest ngrx

It implements a stream architecture that creates client-side storage that any component can subscribe to, and can update it without creating race conditions.

0
May 20 '19 at 10:53
source share



All Articles