Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 - Share data between components using services

I have an object that I want to share between my components into an Angular2 app.

Here is the source of the first component:

/* app.component.ts */  // ...imports import {ConfigService} from './config.service';  @Component({     selector: 'my-app',     templateUrl: 'app/templates/app.html',     directives: [Grid],     providers: [ConfigService] }) export class AppComponent {     public size: number;     public square: number;      constructor(_configService: ConfigService) {         this.size = 16;         this.square = Math.sqrt(this.size);          // Here I call the service to put my data         _configService.setOption('size', this.size);         _configService.setOption('square', this.square);     } } 

and the second component:

/* grid.component.ts */  // ...imports import {ConfigService} from './config.service';  @Component({     selector: 'grid',     templateUrl: 'app/templates/grid.html',     providers: [ConfigService] }) export class Grid {     public config;     public header = [];      constructor(_configService: ConfigService) {         // issue is here, the _configService.getConfig() get an empty object          // but I had filled it just before         this.config = _configService.getConfig();     }   } 

and finally my little service, the ConfigService:

/* config.service.ts */  import {Injectable} from 'angular2/core';  @Injectable() export class ConfigService {      private config = {};      setOption(option, value) {         this.config[option] = value;     }      getConfig() {         return this.config;     } } 

My data are not shared, in the grid.component.ts, the _configService.getConfig() line return an empty object, but it is filled just before in the app.component.ts.

I read the docs and tutorials, nothing worked.

What am I missing ?

Thanks

SOLVED

My issue was that I was injecting my ConfigService twice. In the bootstrap of the application and in the file where I'm using it.

I removed the providers setting and its worked !

like image 681
keversc Avatar asked Feb 08 '16 15:02

keversc


People also ask

Is it a good practice to pass data using services?

The suggested way for those interactions is via bindings (Input/Output). However, if the data does not belong to the parent component, a service is probably the better way. It is more clear and keeps the data hierarchy concise. For components that are not close in the hierarchy, a service is probably the only way.

How do you emit data from one component to another?

Child to parent component If you want to pass data from the child component to the parent component use @Output() and EventEmitter. To pass data from the child to the parent, you have to emit it from the child. The parent will be listening for the event will grab the data.


2 Answers

You define it within your two components. So the service isn't shared. You have one instance for the AppComponent component and another one for the Grid component.

@Component({   selector: 'my-app',   templateUrl: 'app/templates/app.html',   directives: [Grid],   providers: [ConfigService] }) export class AppComponent {   (...) } 

The quick solution is to remove the providers attribute to your Grid component... This way the service instance will be shared by the AppComponent and its children components.

The other solution is to register the corresponding provider within the bootstrap function. In this case, the instance will be shared by the whole application.

bootstrap(AppComponent, [ ConfigService ]); 

To understand why you need to do that, you need to be aware of the "hierarchical injectors" feature of Angular2. Following links could be useful:

  • What's the best way to inject one service into another in angular 2 (Beta)?
  • https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html
like image 116
Thierry Templier Avatar answered Sep 26 '22 14:09

Thierry Templier


For the latest version of angular, if you want to share the service, you can't add it to the bootstrap function. Just add it to the NgModule providers list as you would do with a normal service, its default behaviour will be singleton.

bootstrap(AppComponent);

@NgModule({     declarations: [         ....     ],     imports: [        ....          ],     providers: [         ConfigService, .... 
like image 43
Mike D Avatar answered Sep 22 '22 14:09

Mike D