Get and update a string through a service in Angular 2

Dan picture Dan · May 21, 2016 · Viewed 12.3k times · Source

I'm trying to better understand services by means of a very simple application which gets and updates the value of string within a service and displays it in a component.

Here's the service:

import {Injectable} from 'angular2/core';

@Injectable()
export class SharedService {
  dataString: string;

  insertData(data) {
    this.dataString = data
  }
}

Here's the main 'app' component:

import {Component}      from 'angular2/core';
import {OtherComponent} from './other';
import {SharedService}  from'./shared.service';

@Component({
  selector: 'my-app',
  providers: [SharedService],
  directives: [OtherComponent],
  template: `
    <input type="text" #someValue>
    <button (click)="setSharedValue(someValue.value)">Change value in shared service</button>
    <br><br>
    <other></other>
  `
})
export class AppComponent { 
  constructor(private _sharedService: SharedService){}

  setSharedValue(value){
    this._sharedService.insertData(value);
  }

}

...and here's the 'other' component:

import {Component, OnInit} from 'angular2/core';
import {SharedService} from './shared.service';

@Component({
  selector : "other",
  template : `
    I'm the other component. The shared data is: 
    <p>{{data}}</p>
  `,
})
export class OtherComponent implements OnInit{
  data: string;
  constructor(private _sharedService: SharedService){}
  ngOnInit() {
    this.data = this._sharedService.dataString;
  }
}

Here's a plunkr.

When text is added to the input and the button is clicked I want to display the value entered in the 'other' component, just to demonstrate getting and setting the service data. However, it's just silently failing.

Can anyone explain what I'm doing wrong?

Thanks

Answer

tibbus picture tibbus · May 21, 2016

Your code is correct, it's just your other component do not know that you updated the service, so it will not request a new Data. For this case Angular2 is using Observables :

The Service :

@Injectable()
export class SharedService {
  // Observable string source
  private dataStringSource = new Subject<string>();

  // Observable string stream
  dataString$ = this.dataStringSource.asObservable();

  // Service message commands
  insertData(data: string) {
    this.dataStringSource.next(data)
  }
}

The Main Component

@Component({
  selector: 'my-app',
  providers: [SharedService],
  directives: [OtherComponent],
  template: `
    <input type="text" #someValue>
    <button (click)="setSharedValue(someValue.value)">Change value in shared service</button>
    <br><br>
    <other></other>
  `
})
export class AppComponent { 
  constructor(private _sharedService: SharedService){}

  setSharedValue(value){ 
    this._sharedService.insertData(value);
  }
}

The Other Component

@Component({
  selector : "other",
  template : `
    I'm the other component. The shared data is: 
    <p>{{data}}</p>
  `,
})
export class OtherComponent implements OnInit{
  data: string;
  constructor(private _sharedService: SharedService){}

  ngOnInit() {
    this._sharedService.dataString$.subscribe(
      data => {
        this.data = data; 
      });
  }
}

The updated plunker can be found here : https://plnkr.co/edit/neM6EdYYUkGkRpF0fKGS?p=preview

Interaction between components in Angular2 can be found here : https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service