如何为非父子Angular 2组件创建服务

我真的很难为“无关的”Angular 2组件创建服务 . 但是,父子关系没有问题(我使用绑定或事件 Launcher ) .

我有3个文件:

  • StatsService应该携带数据 .

  • MatchBoard组件,用于生成足球镜头

  • StatsComponent可以在屏幕上打印拍摄张数 .

但是我已经阅读了官方的A2文档并且仍然无法找到解决方案,因此我已经处理了几个小时了 .

我想要的是:我只想生成镜头(每2秒),用服务 grab 它们并发送到StatsComponent,以便它显示屏幕上的镜头数量 . 那很简单 .

StatsService组件

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组件

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

}

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

在控制台中,我从MatchBoard组件获得 'matchboard received this: 2 (then 3, then 4 like normal)' . 但问题始于StatsComponent - 它在'subscribe'之后立即卡住并且始终只记录'0' .

我尝试在statsComponent中的某个地方调用onHomeTeamShot(),但它从一开始就一直显示“1”并且也不会改变 .

回答(2)

3 years ago

原因是这条线

providers: [StatsService]

在StatsComponent中 . 这意味着StatsComponent拥有自己的服务实例 . 解决方案是让组件中的提供程序仅在三个组件之上,并从StatsComponent中删除该行 .

你可以在这里找到更多相关信息:https://angular.io/guide/hierarchical-dependency-injection

3 years ago

将所有逻辑转移到服务上,并利用 Observables 的强大功能来完成繁重的工作 .

在您的服务中,使用 .interval() 创建一个Observable . 这将照顾您的投票 . 您甚至不需要 publishData() ,因为您已经在使用 Subject . 我创建了一个名为 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.
    }

}

现在,要 MatchBoard 组件中的"start"倒计时,只需订阅 generateShots()

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

要在 StatsComponent 中显示您的镜头,请订阅您的 homeTeamShots$ Subject

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

瞧,您有两个组件通过单个共享服务(单例)同步数据 . 清洁 .