全球活动在angular2
在Angular 2中没有相当于$scope.emit()
或$scope.broadcast()
吗?
我知道EventEmitter
function,但据我所知,只是将事件发送到父HTML元素。
如果我需要在fx之间进行通信呢? 兄弟之间或者DOM根部的组件和嵌套深度几个级别的元素之间?
没有等同于Angular 1中的$scope.emit()
或$scope.broadcast()
。组件中的EventEmitter接近,但正如您所提到的那样,它只会将事件发送给直接父组件。
在Angular 2中,还有其他的select,我将在下面进行解释。
@Input()绑定允许将应用程序模型连接到有向对象图(根到叶)。 组件的更改检测器策略的默认行为是将所有更改传播到应用程序模型,以获取来自任何连接组件的所有绑定。
除此之外:有两种types的模型:查看模型和应用模型。 应用程序模型通过@Input()绑定连接。 视图模型只是一个组件属性(未用@Input()装饰),它绑定在组件的模板中。
回答你的问题:
如果我需要在兄弟组件之间进行通信呢?
-
共享应用程序模型 :兄弟姐妹可以通过共享应用程序模型进行通信(就像angular1一样)。 例如,当一个兄弟对模型进行更改时,绑定到相同模型的另一个兄弟会自动更新。
-
组件事件 :子组件可以使用@Output()绑定向父组件发出事件。 父组件可以处理事件,并操纵应用程序模型或它自己的视图模型。 对应用程序模型的更改会自动传播到直接或间接绑定到同一模型的所有组件。
-
服务事件 :组件可以订阅服务事件。 例如,两个兄弟组件可以订阅相同的服务事件,并通过修改它们各自的模型进行响应。 更多关于这个下面。
如何在根组件和深度嵌套的组件之间进行通信?
- 共享应用程序模型 :应用程序模型可以通过@Input()绑定从根组件传递到深度嵌套的子组件。 来自任何组件的模型更改将自动传播到共享相同模型的所有组件。
- 服务事件 :您也可以将EventEmitter移动到共享服务,这允许任何组件注入服务并订阅事件。 这样一来,Root组件可以调用一个服务方法(通常会改变模型),然后发出一个事件。 多层下来,也注入了服务和订阅相同的事件,一个大孩子组件可以处理它。 任何更改共享应用程序模型的事件处理程序都会自动传播到依赖于它的所有组件。 这可能与Angular 1中的
$scope.broadcast()
最接近。下一节将更详细地描述这个想法。
使用服务事件传播更改的可观察服务的示例
以下是使用服务事件传播更改的可观察服务的示例。 当添加一个TodoItem时,该服务发出一个事件通知其组件订户。
export class TodoItem { constructor(public name: string, public done: boolean) { } } export class TodoService { public itemAdded$: EventEmitter<TodoItem>; private todoList: TodoItem[] = []; constructor() { this.itemAdded$ = new EventEmitter(); } public list(): TodoItem[] { return this.todoList; } public add(item: TodoItem): void { this.todoList.push(item); this.itemAdded$.emit(item); } }
以下是根组件如何订阅事件:
export class RootComponent { private addedItem: TodoItem; constructor(todoService: TodoService) { todoService.itemAdded$.subscribe(item => this.onItemAdded(item)); } private onItemAdded(item: TodoItem): void { // do something with added item this.addedItem = item; } }
嵌套深度较深的子组件将以相同的方式订阅事件:
export class GrandChildComponent { private addedItem: TodoItem; constructor(todoService: TodoService) { todoService.itemAdded$.subscribe(item => this.onItemAdded(item)); } private onItemAdded(item: TodoItem): void { // do something with added item this.addedItem = item; } }
以下是调用服务来触发事件的组件(它可以驻留在组件树中的任何位置):
@Component({ selector: 'todo-list', template: ` <ul> <li *ngFor="#item of model"> {{ item.name }} </li> </ul> <br /> Add Item <input type="text" #txt /> <button (click)="add(txt.value); txt.value='';">Add</button> ` }) export class TriggeringComponent{ private model: TodoItem[]; constructor(private todoService: TodoService) { this.model = todoService.list(); } add(value: string) { this.todoService.add(new TodoItem(value, false)); } }
参考: angular度2中的变化检测
下面的代码作为在Angular 2中用$ scope.emit()或$ scope.broadcast()来replace使用共享服务来处理事件的示例。
import {Injectable} from 'angular2/core'; import * as Rx from 'rxjs/Rx'; @Injectable() export class EventsService { constructor() { this.listeners = {}; this.eventsSubject = new Rx.Subject(); this.events = Rx.Observable.from(this.eventsSubject); this.events.subscribe( ({name, args}) => { if (this.listeners[name]) { for (let listener of this.listeners[name]) { listener(...args); } } }); } on(name, listener) { if (!this.listeners[name]) { this.listeners[name] = []; } this.listeners[name].push(listener); } broadcast(name, ...args) { this.eventsSubject.next({ name, args }); } }
用法示例:
广播:
function handleHttpError(error) { this.eventsService.broadcast('http-error', error); return ( Rx.Observable.throw(error) ); }
监听器:
import {Inject, Injectable} from "angular2/core"; import {EventsService} from './events.service'; @Injectable() export class HttpErrorHandler { constructor(eventsService) { this.eventsService = eventsService; } static get parameters() { return [new Inject(EventsService)]; } init() { this.eventsService.on('http-error', function(error) { console.group("HttpErrorHandler"); console.log(error.status, "status code detected."); console.dir(error); console.groupEnd(); }); } }
它可以支持多个参数:
this.eventsService.broadcast('something', "Am I a?", "Should be b", "C?"); this.eventsService.on('something', function (a, b, c) { console.log(a, b, c); });
我正在使用包装rxjs Subject
(TypeScript)的消息服务
Plunker示例:消息服务
import { Injectable } from '@angular/core'; import { Subject } from 'rxjs/Subject'; import { Subscription } from 'rxjs/Subscription'; import 'rxjs/add/operator/filter' import 'rxjs/add/operator/map' interface Message { type: string; payload: any; } type MessageCallback = (payload: any) => void; @Injectable() export class MessageService { private handler = new Subject<Message>(); broadcast(type: string, payload: any) { this.handler.next({ type, payload }); } subscribe(type: string, callback: MessageCallback): Subscription { return this.handler .filter(message => message.type === type) .map(message => message.payload) .subscribe(callback); } }
组件可以订阅和广播事件(发件人):
import { Component, OnDestroy } from '@angular/core' import { MessageService } from './message.service' import { Subscription } from 'rxjs/Subscription' @Component({ selector: 'sender', template: ... }) export class SenderComponent implements OnDestroy { private subscription: Susbcription; private messages = []; private messageNum = 0; private name = 'sender' constructor(private messageService: MessageService) { this.subscription = messageService.subscribe(this.name, (payload) => { this.messages.push(payload); }); } send() { let payload = { text: `Message ${++this.messageNum}`, respondEvent: this.name } this.messageService.broadcast('receiver', payload); } clear() { this.messages = []; } ngOnDestroy() { this.subscription.unsubscribe(); } }
(接收器)
import { Component, OnDestroy } from '@angular/core' import { MessageService } from './message.service' import { Subscription } from 'rxjs/Subscription' @Component({ selector: 'receiver', template: ... }) export class ReceiverComponent implements OnDestroy { private subscription: Susbcription; private messages = []; constructor(private messageService: MessageService) { this.subscription = messageService.subscribe('receiver', (payload) => { this.messages.push(payload); }); } send(message: {text: string, respondEvent: string}) { this.messageService.broadcast(message.respondEvent, message.text); } clear() { this.messages = []; } ngOnDestroy() { this.subscription.unsubscribe(); } }
MessageService
的subscribe
方法返回一个rxjs Subscription
对象,可以像这样取消订阅:
import { Subscription } from 'rxjs/Subscription'; ... export class SomeListener { subscription: Subscription; constructor(private messageService: MessageService) { this.subscription = messageService.subscribe('someMessage', (payload) => { console.log(payload); this.subscription.unsubscribe(); }); } }
另请参阅此答案: https : //stackoverflow.com/a/36782616/1861779
Plunker示例:消息服务
您可以使用EventEmitter或Observables来创build您在DI中注册的事件总线服务。 每个想要参与的组件都只是请求服务作为构造参数,并发出和/或订阅事件。
也可以看看
- https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
- 代表团:Angular2中的EventEmitter或Observable
不要使用 EventEmitter进行服务通信。
你应该使用Observabletypes之一。 我个人喜欢BehaviorSubject。
简单的例子:
你可以传递初始状态,在这里我传递null
let subject = new BehaviorSubject(null);
当你想更新主题
subject.next(myObject的)
从任何服务或组件观察,并获得新的更新时采取行动。
subject.subscribe(this.YOURMETHOD);
这里是更多的信息。 。
我在这里创build了一个pub-sub示例:
http://www.syntaxsuccess.com/viewarticle/pub-sub-in-angular-2.0
这个想法是使用RxJs主题连接Observer和Observable作为发射和订阅自定义事件的通用解决scheme。 在我的示例中,我使用客户对象进行演示
this.pubSubService.Stream.emit(customer); this.pubSubService.Stream.subscribe(customer => this.processCustomer(customer));
这里还有一个现场演示: http : //www.syntaxsuccess.com/angular-2-samples/#/demo/pub-sub
我们实现了一个ngModelChange observable指令,它通过在你自己的组件中实例化的事件发送器发送所有的模型改变。 你只需要绑定你的事件发射器的指令。
请参阅: https : //github.com/atomicbits/angular2-modelchangeobservable
在html中,绑定你的事件发射器(在这个例子中是countryChanged):
<input [(ngModel)]="country.name" [modelChangeObservable]="countryChanged" placeholder="Country" name="country" id="country"></input>
在您的打字稿组件中,对EventEmitter执行一些asynchronous操作:
import ... import {ModelChangeObservable} from './model-change-observable.directive' @Component({ selector: 'my-component', directives: [ModelChangeObservable], providers: [], templateUrl: 'my-component.html' }) export class MyComponent { @Input() country: Country selectedCountries:Country[] countries:Country[] = <Country[]>[] countryChanged:EventEmitter<string> = new EventEmitter<string>() constructor() { this.countryChanged .filter((text:string) => text.length > 2) .debounceTime(300) .subscribe((countryName:string) => { let query = new RegExp(countryName, 'ig') this.selectedCountries = this.countries.filter((country:Country) => { return query.test(country.name) }) }) } }
这是我的版本:
export interface IEventListenr extends OnDestroy{ ngOnDestroy(): void } @Injectable() export class EventManagerService { private listeners = {}; private subject = new EventEmitter(); private eventObserver = this.subject.asObservable(); constructor() { this.eventObserver.subscribe(({name,args})=>{ if(this.listeners[name]) { for(let listener of this.listeners[name]) { listener.callback(args); } } }) } public registerEvent(eventName:string,eventListener:IEventListenr,callback:any) { if(!this.listeners[eventName]) this.listeners[eventName] = []; let eventExist = false; for(let listener of this.listeners[eventName]) { if(listener.eventListener.constructor.name==eventListener.constructor.name) { eventExist = true; break; } } if(!eventExist) { this.listeners[eventName].push({eventListener,callback}); } } public unregisterEvent(eventName:string,eventListener:IEventListenr) { if(this.listeners[eventName]) { for(let i = 0; i<this.listeners[eventName].length;i++) { if(this.listeners[eventName][i].eventListener.constructor.name==eventListener.constructor.name) { this.listeners[eventName].splice(i, 1); break; } } } } emit(name:string,...args:any[]) { this.subject.next({name,args}); } }
使用:
export class <YOURCOMPONENT> implements IEventListener{ constructor(private eventManager: EventManagerService) { this.eventManager.registerEvent('EVENT_NAME',this,(args:any)=>{ .... }) } ngOnDestroy(): void { this.eventManager.unregisterEvent('closeModal',this) }
}
发射:
this.eventManager.emit("EVENT_NAME");
服务事件:组件可以订阅服务事件。 例如,两个兄弟组件可以订阅相同的服务事件,并通过修改它们各自的模型进行响应。 更多关于这个下面。
但是一定要取消对父组件的销毁。
我最喜欢的做法是在我的服务中使用行为主体或事件发射器(几乎相同)来控制我的所有子组件。
使用angular度cli,运行gs创build一个新的服务,然后使用BehaviorSubject或EventEmitter
export Class myService { #all the stuff that must exist myString: string[] = []; contactChange : BehaviorSubject<string[]> = new BehaviorSubject(this.myString); getContacts(newContacts) { // get your data from a webservices & when you done simply next the value this.contactChange.next(newContacts); } }
当你这样做的时候,每个使用你的服务作为提供者的组件都会意识到这个改变。 只需订阅结果,就像使用eventEmitter一样;)
export Class myComp { #all the stuff that exists like @Component + constructor using (private myService: myService) this.myService.contactChange.subscribe((contacts) => { this.contactList += contacts; //run everytime next is called } }
- 在C#事件处理程序中,为什么必须将“sender”参数作为对象?
- jquery asp.netbutton通过ajax点击事件
- Window.Loaded和Window.ContentRendered事件有什么区别
- 在Visual Studio中KeyDown事件,KeyPress事件和KeyUp事件之间的区别
- HTML / CSS:让一个div“隐身”点击?
- C#:引发一个inheritance的事件
- 从onclick / onchange事件获取HTMLcheckbox的价值
- jQuery – 从DOM中删除元素时触发事件
- 用于“Ctrl”/“Shift”+鼠标左键单击的JavaScript或jQuery事件处理程序