简体   繁体   English

Angular2:无法订阅从共享服务发出的自定义事件

[英]Angular2: Cannot subscribe to custom events emitted from shared service

I've started learning Angular2 and I'm having trouble with custom events using emit/subscribe. 我已经开始学习Angular2,并且在使用发出/订阅的自定义事件时遇到了麻烦。

I created a little demo to demonstrate: Plunker 我创建了一个小演示来演示: Plunker

As you can see, there is a PreviewService class. 如您所见,这里有一个PreviewService类。 This class has a setURL(url: string) method, that, if invoked, emits a contentUrlChange$ event. 此类具有setURL(url:string)方法,如果调用该方法,则将发出contentUrlChange $事件。

src/services/preview.service.ts SRC /服务/ preview.service.ts

import {Injectable, EventEmitter} from 'angular2/core';

@Injectable()
export class PreviewService {

  private _url: string;

  contentUrlChange$: EventEmitter<any>;

  constructor() {
    this.contentUrlChange$ = new EventEmitter;
  };

  setURL(url: string): void {
    this._url = url;
    this.contentUrlChange$.emit(url);
  };

}

In the constructor function of the App component, I subscribe to the PreviewService's contentUrlChange$ event. 在App组件的构造函数中,我订阅了PreviewService的contentUrlChange $事件。 If you run the Plunker, you will see the alert window. 如果运行柱塞,则将看到警报窗口。

src/app.ts SRC / app.ts

[...]
constructor(private _previewService: PreviewService) {
  _previewService.contentUrlChange$.subscribe(url => {
    alert("APP " + url);
  })

  _previewService.setURL('http://www.example.com');
};
[...]

But here is my problem: I have another component, PreviewComponent, and in that component's constructor function, just like in the App component's constructor function, I subscribe to the PreviewService's contentUrlChange$ event. 但这是我的问题:我有另一个组件PreviewComponent,并且在该组件的构造函数中,就像在App组件的构造函数中一样,我订阅了PreviewService的contentUrlChange $事件。 But strangely, the alert window that should appear, does not. 但是奇怪的是,应该出现的警报窗口却没有。

src/component/preview.component.ts SRC /组件/ preview.component.ts

constructor(private _previewService: PreviewService) {
  _previewService.contentUrlChange$.subscribe(url => {
    alert("PREVIEW " + url); // Nothing happens here
  })
};

I read through a couple of questions/answers, which indicate that what I'm doing should be working, but still no success. 我通读了几个问题/答案,它们表明我正在做的事情应该可以正常工作,但仍然没有成功。 Any thoughts/solutions would be greatly appreciated. 任何想法/解决方案将不胜感激。 Thx. 谢谢。

There where few issues with your plunk. 那里的pl子问题很少。 First things first, if you inject separate instances of service to your components, they won't be able to subscribe to same event, simply because they will be different variables(properties). 首先,如果将单独的服务实例注入到组件,则它们将无法订阅同一事件,仅因为它们将是不同的变量(属性)。 So you must provide same service for every component, simply do in bootstrap of your application: 因此,您必须为每个组件提供相同的服务,只需在应用程序的引导中进行即可:

bootstrap(App, [
  YourService
]).catch(...)

Secondly, you are emmiting value from app component when child component( PreviewComponent ) is not yet initialized . 其次,当子组件( PreviewComponent尚未初始化时,您正在从应用程序组件中释放值。 To wait, you could use setTimeout(func, 0) (but this is hack and I wouldn't recomend this), or simply use built in angular's OnInit lifecycle hook 等待,您可以使用setTimeout(func, 0) (但这是hack,我不建议这样做),或仅使用内置的angular的OnInit生命周期挂钩

import {OnInit} from 'angular2/core';

...


ngOnInit() {
  // emit values here
}

Here is updated plunk: http://plnkr.co/edit/okiNPFRKKYXfce1P0D5o 这是更新的插件: http : //plnkr.co/edit/okiNPFRKKYXfce1P0D5o

The problem is that each component gets it's own instance of the service. 问题在于每个组件都获得自己的服务实例。

A singleton service must be configured as a provider while bootstrapping the application. 在引导应用程序时,必须将单例服务配置为提供程序。 In your case this would be in main.ts 在您的情况下,这将在main.ts中

import {bootstrap} from 'angular2/platform/browser';
import {App} from './app';
import {PreviewService} from './services/preview.service';

bootstrap(App, [PreviewService]) // configure the PreviewService as a singleton for the entire application.
  .catch(err => console.error(err));

Then you must remove it as a provider for any particular component. 然后,您必须将其删除为任何特定组件的提供者。

app.ts app.ts

import {PreviewService} from './services/preview.service';
import {PreviewComponent} from './components/preview.component';

@Component({
  selector: 'my-app',
  template: `<preview></preview>`,
  directives: [ PreviewComponent ]
})

preview.component.ts preview.component.ts

import {Component} from 'angular2/core';
import {PreviewService} from '../services/preview.service';

@Component({
   selector: 'preview',
   template: ``
})

Another thing is that the constructor of the App component will be called before the constructor of the PreviewComponent . 另一件事是, App组件的构造函数将在PreviewComponent的构造函数之前调用。

That means if you make the URL change in the App constructor the PreviewComponent will not have subscribed yet. 这意味着,如果您在App构造函数中更改URL,则PreviewComponent尚未订阅。

I fixed it by making the change on a timeout, I guess that will differ in real life. 我通过对超时进行更改来解决它,我想这在现实生活中会有所不同。

export class App {
  constructor(private _previewService: PreviewService) {
    console.log('app created');
    _previewService.contentUrlChange$.subscribe(url => {
      alert("APP " + url);
    })

    setTimeout(() => {
      alert('setting url');
      _previewService.setURL('http://www.example.com');  
    }, 1000); 

  }
}

You can see the corrected plunker here . 您可以在此处看到校正后的松节器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM