2017-06-29 3 views
0

Ich bin wirklich fest mit der Erstellung eines Dienstes für "nicht verwandte" Angular 2-Komponenten. Es gibt jedoch keine Probleme mit Eltern-Kind-Beziehungen (ich verwende Binding- oder Event-Emitter).So erstellen Sie einen Dienst für nicht Eltern-Kind-Angular 2-Komponenten

Ich habe 3 Dateien:

  1. StatsService, die Daten tragen sollte.
  2. MatchBoard Komponente, die Fußballschüsse generiert
  3. StatsComponent, die Anzahl der Aufnahmen auf den Bildschirm druckt.

Aber ich habe mich damit seit Stunden beschäftigt, nachdem ich die offizielle A2-Dokumentation gelesen habe und immer noch keine Lösung finde.

WAS ICH WÜNSCHE: Ich will nur Schüsse (alle 2 Sek.) Generieren, sie mit dem Service greifen und in StatsComponent senden, so dass es die Anzahl der Schüsse auf dem Bildschirm anzeigt. So einfach.

Die StatsService Komponente

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

} 

spund Komponente

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

} 

Und 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 der Konsole ich ‚get spund diese erhalten: 2 (dann 3, dann 4 wie normal) ' von der MatchBoard com Teil. Aber das Problem beginnt in StatsComponent - es bleibt direkt nach 'subscribe' stecken und protokolliert nur '0' die ganze Zeit.

Ich habe versucht, onHomeTeamShot() irgendwo in statsComponent aufrufen, aber es zeigt "1" die ganze Zeit von Anfang an und ändert sich auch nicht.

Antwort

1

Der Grund dafür ist die Linie

providers: [StatsService] 

im StatsComponent. Das bedeutet, dass die StatsComponent eine eigene Instanz des Dienstes besitzt. Die Lösung ist, den Anbieter in der Komponente über den drei Komponenten nur zu haben und die Zeile von StatsComponent zu entfernen.

Sie können mehr Informationen über das hier finden: https://angular.io/guide/hierarchical-dependency-injection

+0

Omg, das habe ich nicht einmal bemerkt ... 12 Stunden verschwendet ... :) vielen Dank! Es funktioniert jetzt. –

1

Umschalttaste alle Ihre Logik auf den Dienst, und nutzen die Kraft des Observables das schwere Heben zu tun.

In Ihrem Service erstellen Sie ein Observable mit .interval(). Dies wird sich um Ihre Umfrage kümmern. Sie brauchen nicht einmal die publishData(), da Sie bereits eine Subject verwenden.Ich habe eine Funktion 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. 
    } 

} 

Jetzt genannt, zu Countdown in Ihre MatchBoard Komponente "Start", abonnieren Sie einfach generateShots():

ngOnInit() { 
    this._statsService.generateShots() 
     .subscribe(shots => this.homeTeamShots = shots); 
    //this.homeTeamShots will increment from 0 to 1,2,3.... every 2000ms 
} 

Und Ihre Aufnahmen in StatsComponent anzuzeigen, abonnieren Sie Ihre homeTeamShots$Subject :

ngOnInit() { 
    this._statsService.homeTeamShots$.subscribe(
     data => { 
      this.homeTeamShots = data; 
      console.log('Sibling2Component-received from sibling1: ' + data); 
     } 
    ); 
} 

Und voila, du hast zwei Componen ts synchronisieren die Daten über einen einzigen gemeinsamen Dienst (Singleton). Reinigen.

+0

Vielen Dank, ich bin neu in Reactive stuff und Angular, aber ich werde versuchen zu lernen, indem ich es tue :) Ich werde die App wirklich wiederholen, um die Dinge über den Service zu behandeln –

Verwandte Themen