Reputation: 968
I'm really stuck with creating a service for "unrelated" Angular 2 components. There are no problems, however, with parent-child relations (I use binding or event emitter).
I have 3 files:
But I've been dealing with this for hours now, having read the official A2 documentation and still cannot figure out a solution.
WHAT I WANT: I just want to generate shots (every 2 sec), grab them with the service and send into StatsComponent so that it displays the number of shots on the screen. That simple.
The StatsService component
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class StatsService {
private homeTeamShots = new Subject<any>();
homeTeamShots$ = this.homeTeamShots.asObservable();
publishData(data:any){
this.homeTeamShots.next(data);
}
}
MatchBoard component
import { Component, Input, OnInit, OnChanges } from '@angular/core';
import {StatsService} from '../stats.component/stats.service';
@Component({
selector: 'match-board',
templateUrl: './matchboard.component.html',
styleUrls: ['./matchboard.component.css']
})
export class MatchBoard implements OnChanges {
homeTeamShots:number = 0;
constructor(private _statsService:StatsService) {
this._statsService.homeTeamShots$.subscribe(
data => {
console.log('matchboard received this: ' + data);
}
)
}
ngOnChanges(){
}
onHomeTeamShot(){
this.homeTeamShots += 1;
this._statsService.publishData(this.homeTeamShots);
}
ngOnInit(){
// shots are taken every 2 seconds as a example
setInterval(()=> this.onHomeTeamShot(), 2000);
}
}
And StatsComponent
import { Component, Input, OnInit, OnChanges } from '@angular/core';
import {StatsService} from '../stats.component/stats.service';
@Component({
selector: 'stats',
templateUrl: './stats.component.html',
styleUrls: ['./stats.component.css'],
providers: [StatsService]
})
export class StatsComponent implements OnChanges {
homeTeamShots:number;
constructor(private _statsService:StatsService) {
this.homeTeamShots = 0;
this._statsService.homeTeamShots$.subscribe(
data => {
this.homeTeamShots = data;
console.log('Sibling2Component-received from sibling1: ' + data);
}
);
}
ngOnChanges(){
}
onHomeTeamShot() {
this.homeTeamShots += 1;
console.log('number of shots in stats now ' + this.homeTeamShots);
this._statsService.publishData(this.homeTeamShots);
}
ngOnInit(){
setInterval(()=> console.log(this.homeTeamShots), 2050);
}
}
In the console, I get 'matchboard received this: 2 (then 3, then 4 like normal)' from the MatchBoard component. But the problem begins in StatsComponent - it gets stuck right after 'subscribe' and logs just '0' all the time.
I tried calling onHomeTeamShot() somewhere in statsComponent but it shows '1' all the time from the beginning and does not change either.
Upvotes: 0
Views: 72
Reputation: 8478
Shift all your logic to the service, and leverage the power of Observables
to do the heavy lifting.
In your service, create an Observable using .interval()
. This will take care of your polling. You do not even need the publishData()
since you are already using a Subject
. I created a function called generateShots()
import {Injectable} from '@angular/core';
import {Subject} from 'rxjs/Subject';
@Injectable()
export class StatsService {
private homeTeamShots = new Subject<any>();
homeTeamShots$ = this.homeTeamShots.asObservable();
generateShots() {
return Observable.interval(2000)
.map(ticks => this.homeTeamShots$.next(ticks));
//.interval() returns a single integer, starting from 0,1,2....
//just simply update your subject with that value.
}
}
Now, to "start" countdown in your MatchBoard
component, simply subscribe to generateShots()
:
ngOnInit() {
this._statsService.generateShots()
.subscribe(shots => this.homeTeamShots = shots);
//this.homeTeamShots will increment from 0 to 1,2,3.... every 2000ms
}
And to display your shots in StatsComponent
, subscribe to your homeTeamShots$
Subject
:
ngOnInit() {
this._statsService.homeTeamShots$.subscribe(
data => {
this.homeTeamShots = data;
console.log('Sibling2Component-received from sibling1: ' + data);
}
);
}
And voila, you got two components syncing the data through a single shared service (singleton). Clean.
Upvotes: 1
Reputation: 1272
The reason is the line
providers: [StatsService]
in the StatsComponent. That means the StatsComponent has an own instance of the service. The solution is to have the provider in the component above the three components only and remove the line from StatsComponent.
You can find some more information about that here: https://angular.io/guide/hierarchical-dependency-injection
Upvotes: 1