【问题标题】:Angular 4 emitting and subscribing to an event in a shared serviceAngular 4在共享服务中发出和订阅事件
【发布时间】:2018-01-03 05:32:38
【问题描述】:

我正在我的主要组件中发出一个事件:

main.component.ts

this.sharedService.cartData.emit(this.data);

这是我的 sharedService.ts

import { Component, Injectable, EventEmitter } from '@angular/core';
export class SharedService {
    cartData = new EventEmitter<any>();
} 

在我的另一个(子)组件中,我想访问这个值,但不知何故,订阅不起作用:

dashboard.ts

private myData: any;

constructor(private sharedService: SharedService) {
    this.sharedService.cartData.subscribe(
        (data: any) => myData = data,
        error => this.errorGettingData = <any>error,
        () => this.aggregateData(this.myData));
}

我错过了什么吗?当我将数据作为 Injectable 传递时,它工作正常。 在一些 REST 调用之后发出事件(在主组件中)。

更新

所以问题是子组件是在事件第一次发出之后创建的。我想在这种情况下最好将数据直接注入subcompnent

【问题讨论】:

  • 您在哪里提供共享服务?服务的实例可能不一样,如果你在不同的模块中提供服务,就会发生这种情况。
  • 我在父 app.module.ts 提供者中声明了它:[SharedService ...],
  • 如何同时加载两个组件?在不同的路线?
  • 你用@Injectable()装饰服务了吗?
  • 对于 main.components.ts,我确实使用了路由,但仪表板组件是在 main.component.html 中作为选择器 () 创建的。

标签: angular typescript subscription eventemitter sharedservices


【解决方案1】:

更新: Plunker 示例不再维护,请使用 StackBlitz 这里的例子 https://stackblitz.com/edit/stackoverflow-questions-45351598-angular?file=src%2Fapp%2Fapp.component.ts

我使用您上面提供的代码创建了一个有效的 plunker 示例。 https://plnkr.co/edit/LS1uqB?p=preview

import { Component, NgModule, Injectable, EventEmitter, AfterViewInit } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';


@Injectable()
export class SharedService {
    cartData = new EventEmitter<any>();
} 

@Component({
  selector: 'app-app',
  template: `
    <h1>
      Main Component <button (click)="onEvent()">onEvent</button>
    </h1>
    <p>
      <app-dashboard></app-dashboard>
    </p>
  `,
})
export class App implements AfterViewInit {
  data: any = "Shared Data";

  constructor(private sharedService: SharedService) {
  }

  ngAfterViewInit() {
    this.sharedService.cartData.emit("ngAfterViewInit: " + this.data);
  }

  onEvent() {
    this.sharedService.cartData.emit("onEvent: " + this.data);
  }
}

@Component({
  selector: 'app-dashboard',
  template: `
    <h2>
      Dashboard component
    </h2>
    <p>
      {{myData}}
    </p>
  `,
})
export class AppDashboard implements AfterViewInit {
  myData: any;

  constructor(private sharedService: SharedService) {
          this.sharedService.cartData.subscribe(
          (data: any) => {
            console.log(data);
            this.myData = data;
          });
  }

}


@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, AppDashboard ],
  providers: [ SharedService ],
  bootstrap: [ App ]
})
export class AppModule {}

在此处查看生命周期挂钩 https://angular.io/guide/lifecycle-hooks

【讨论】:

  • 这很好用,因为它与点击监听器一起工作。我试图弄清楚当我在代码中发出事件时必须使用哪个函数。
  • 它也适用于 ngAfterViewInit,它是 Angular 生命周期钩子的一部分。查看angular.io/guide/lifecycle-hooks
  • 我将我的版本更改为 ngAfterViewInit,当我单击某处时它可以工作。最初加载应用程序时,子组件会在第一个事件触发后加载,因为我在 main.component.html 中声明了它。 1) 发射事件 2) 仪表板构造函数 3) 仪表板 AfterViewInit
  • 您能否详细说明单击某处时它起作用的意思?如果它没有按预期运行,请制作一个 plunker 示例,我很乐意尝试解决问题。
  • 是的,抱歉,单击某处是指如果我在页面加载后在事件上发出事件。但正如我在更新的帖子中所描述的,我认为在我的情况下注入数据比发出数据更有意义。
【解决方案2】:

试试这个:

export class SharedService {
    private dataPusher = new Subject<any>();
    cartData = dataPusher.asObservable().pipe(shareReplay(1));

    pushData(value:any) {
       this.dataPusher.next(value);
    }
} 

这样做是它将为“迟到的”订阅者重放最后发出的值。 如果要发出初始值,可以使用BehaviourSubject - 它在构造函数中获取初始值。

或者您可以使用startWith 运算符对其进行管道/链接。

cartData = dataPusher.asObservable().pipe(startWith("someValue"), shareReplay(1));

【讨论】:

    猜你喜欢
    • 2016-08-23
    • 2017-01-20
    • 2016-04-30
    • 1970-01-01
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多