角度 2:使用服务广播事件

Posted

技术标签:

【中文标题】角度 2:使用服务广播事件【英文标题】:angular 2: using a service to broadcast an event 【发布时间】:2018-01-08 20:18:20 【问题描述】:

我试图让一个组件中的按钮单击以将焦点放在另一个组件上的元素上。 (坦率地说,我不明白为什么这一定如此复杂,但我无法实现任何实际可行的更简单的方法。)

我正在使用一项服务。除了 点击发生之外,它不需要传递任何数据。我不确定监听组件是如何响应事件的。

app.component:

跳到主要内容

import  Component  from '@angular/core';
import  SkipToContentService  from './services/skip-to-content.service';


export class AppComponent 
    constructor(
        private skipToContent: SkipToContentService
    ) 
    

    skipLink() 
        this.skipToContent.setClicked();
    


登录组件:

<input type="text" name="username" />


import  Component, OnInit  from '@angular/core';
import  SkipToContentService  from '../../../services/skip-to-content.service';

export class BaseLoginComponent implements OnInit 

    constructor(
        private skipToContent: SkipToContentService
        ) 
    

    ngOnInit() 
        this.skipToContent.skipClicked.subscribe(
            console.log("!")
            // should put focus() on input
        );

    

跳转到内容服务:

import  Injectable, EventEmitter  from '@angular/core';

@Injectable()
export class SkipToContentService 

    skipClicked: EventEmitter<boolean> = new EventEmitter();


    constructor() 
    

    setClicked() 
        console.log('clicked');
        this.skipClicked.emit();
    ;

我有点不知道登录将如何“听到”skipClicked 事件。

【问题讨论】:

您不应该在您的服务***.com/questions/36076700/… 中使用EventEmitter。并使用共享服务来广播事件:angular.io/guide/… 【参考方案1】:

首先,使用BehaviorSubject 而不是EventEmitter。将skipCliekd的声明修改为:

skipClicked: BehaviorSubject<boolean> = new BehaviorSubject(false);

然后,您需要使用next() 方法广播新值,如下所示:

this.skipClicked.next (true);

另外,将您的订阅更改为:

 this.skipToContent.skipClicked.subscribe( value => 
     if (value === true) 
         console.log("!"); 
         // should put focus() on input 
     
 );

【讨论】:

一些问题:1] SafeSubscriber.schedulerFn [as _next] (event_emitter.ts:115) 处的“generatorOrNext 不是函数” 2] 页面加载时会自动触发事件。即我得到的第一件事是'! '。 3] 据我所知,next() 已被弃用,取而代之的是 emit() EventEmmiter,只在组件中使用 EventEmitter 只能在实际组件中使用,Angular 组件集成指南建议在另一个答案中使用共享服务,因此因为答案需要更新或误导他人而投反对票【参考方案2】:

EventEmitter 只能在带有@Output 指令的实际组件中使用。其他任何事情将来都可能无法正常工作。

对于孩子与父母的交流,最好使用主题或行为主题。这是角度指南中的一个示例。

https://angular.io/guide/component-interaction

@Injectable()
export class MissionService 

  // Observable string sources
  private missionAnnouncedSource = new Subject<string>();
  private missionConfirmedSource = new Subject<string>();

  // Observable string streams
  missionAnnounced$ = this.missionAnnouncedSource.asObservable();
  missionConfirmed$ = this.missionConfirmedSource.asObservable();

  // Service message commands
  announceMission(mission: string) 
    this.missionAnnouncedSource.next(mission);
  

  confirmMission(astronaut: string) 
    this.missionConfirmedSource.next(astronaut);
  


提示:

如果您有一个事件只是表示某事已经发生或完成 - 并且没有与之关联的实际数据 - 您可以使用 Subject&lt;void&gt;()。这使得next() 的签名更清晰,您无需为此提供虚拟值。

例如。

windowClosed = new Subject<void>();

windowClosed.next() 将发出事件

【讨论】:

是的,当我只需要服务来做一件事时,我也真的很难过。我什至给它起什么名字?是为组件命名,还是为动作命名,还是为动作类型命名。我想你只需要看看什么对你有用。 要记住的另一件事是您可以组合用于内部数据传输的服务。它们可以相互注入,如果你有一个包含 5 个不相关子的复杂控件,你可以注入 5 个你想要的服务。我希望他们有一个比“服务”更好的名字

以上是关于角度 2:使用服务广播事件的主要内容,如果未能解决你的问题,请参考以下文章

typescript 角度共享事件服务

如何使用角度检测浏览器后退按钮单击事件?

如何使用角度引导日历为重复事件提供 dtStart 和 until?

如何使用 CdkScrollable 检测角度材料 2 自动完成列表上的滚动事件

从 REST 和服务器与客户端事件的角度理解 websocket

角度 2(更改)事件未触发