Angular中没有等价的$scope.emit()或$scope.broadcast()吗?
我知道EventEmitter功能,但据我所知,它只会向父HTML元素发出一个事件。
如果我需要在fx和。还是DOM根组件和嵌套了几层的元素之间?
Angular中没有等价的$scope.emit()或$scope.broadcast()吗?
我知道EventEmitter功能,但据我所知,它只会向父HTML元素发出一个事件。
如果我需要在fx和。还是DOM根组件和嵌套了几层的元素之间?
当前回答
我最喜欢的方法是在我的服务中使用行为主题或事件发射器(几乎相同)来控制我的所有子组件。
使用angular cli,运行ng gs来创建一个新的服务,然后使用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
}
}
其他回答
AngularJS中没有等价的$scope.emit()或$scope.broadcast()。 组件内部的EventEmitter很接近,但正如您所提到的,它只会向直接的父组件发出事件。
在Angular中,还有其他的替代方案,我将在下面解释。
@Input()绑定允许在有向对象图中连接应用程序模型(根到叶)。组件的更改检测器策略的默认行为是将所有更改从任何连接的组件传播到所有绑定的应用程序模型。
旁白:有两种类型的模型:视图模型和应用程序模型。应用程序模型通过@Input()绑定连接。视图模型只是一个绑定在组件模板中的组件属性(没有@Input()装饰)。
回答你的问题:
如果我需要在兄弟组件之间通信怎么办?
Shared Application Model: Siblings can communicate through a shared application model (just like angular 1). For example, when one sibling makes a change to a model, the other sibling that has bindings to the same model is automatically updated. Component Events: Child components can emit an event to the parent component using @Output() bindings. The parent component can handle the event, and manipulate the application model or its own view model. Changes to the Application Model are automatically propagated to all components that directly or indirectly bind to the same model. Service Events: Components can subscribe to service events. For example, two sibling components can subscribe to the same service event and respond by modifying their respective models. More on this below.
我如何在根组件和嵌套了几个层次的组件之间进行通信?
Shared Application Model: The application model can be passed from the Root component down to deeply nested sub-components through @Input() bindings. Changes to a model from any component will automatically propagate to all components that share the same model. Service Events: You can also move the EventEmitter to a shared service, which allows any component to inject the service and subscribe to the event. That way, a Root component can call a service method (typically mutating the model), which in turn emits an event. Several layers down, a grand-child component which has also injected the service and subscribed to the same event, can handle it. Any event handler that changes a shared Application Model, will automatically propagate to all components that depend on it. This is probably the closest equivalent to $scope.broadcast() from Angular 1. The next section describes this idea in more detail.
使用服务事件传播更改的可观察服务示例
下面是一个可观察服务的例子,它使用服务事件传播更改。添加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中的变更检测
不要使用EventEmitter来进行服务通信。
你应该使用Observable类型之一。我个人喜欢BehaviorSubject。
简单的例子:
你可以传递初始状态,这里我传递null
let subject = new BehaviorSubject(null);
当你想要更新主题时
next (myObject)科目。
观察任何服务或组件,并在其获得新的更新时采取行动。
subject.subscribe (this.YOURMETHOD);
这里有更多信息。
服务事件:组件可以订阅服务事件。例如,两个兄弟组件可以订阅相同的服务事件,并通过修改各自的模型进行响应。下文将详细介绍。
但是要确保在销毁父组件时取消订阅。
下面的代码是Angular 2中使用共享服务来处理事件的$scope.emit()或$scope.broadcast()的替换示例。
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);
}
off(name, listener) {
this.listeners[name] = this.listeners[name].filter(x => x != 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);
});
我最喜欢的方法是在我的服务中使用行为主题或事件发射器(几乎相同)来控制我的所有子组件。
使用angular cli,运行ng gs来创建一个新的服务,然后使用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
}
}