Глобальные события в угловых

Нет ли эквивалента $scope.emit() или $scope.broadcast() в Angular?

Я знаю функциональность EventEmitter , но насколько я понимаю, это просто испустит событие в родительский элемент HTML.

Что делать, если мне нужно общаться между fx. братья или сестры или между компонентом в корне DOM, и элемент вложен в несколько уровней в глубину?

10 Solutions collect form web for “Глобальные события в угловых”

Не существует эквивалента $scope.emit() или $scope.broadcast() от AngularJS. EventEmitter внутри компонента близок, но, как вы уже упоминали, он будет выдавать событие только для исходного родительского компонента.

В Angular есть другие альтернативы, которые я попытаюсь объяснить ниже.

Связывание @Input () позволяет модели приложения подключаться в графе направленного объекта (от корня до листьев). Поведение по умолчанию страtagsи детектирования изменений компонента заключается в распространении всех изменений в модель приложения для всех привязок из любого подключенного компонента.

Кроме того, существуют два типа моделей: модели и модели приложений. Модель приложения подключается посредством привязок @Input (). Модель просмотра – это просто свойство компонента (не украшено @Input ()), которое связано в шаблоне компонента.

Чтобы ответить на ваши вопросы:

Что делать, если мне нужно общаться между родственными компонентами?

  1. Общая модель приложения . Братья и сестры могут общаться через общую модель приложения (как и угловое 1). Например, когда один из братьев делает изменение модели, другой брат, имеющий привязки к той же модели, автоматически обновляется.

  2. Компонентные события : дочерние компоненты могут передавать событие родительскому компоненту с помощью привязок @Output (). Родительский компонент может обрабатывать событие и манипулировать моделью приложения или собственной моделью просмотра. Изменения в Application Model автоматически распространяются на все компоненты, которые прямо или косвенно связаны с одной и той же моделью.

  3. Служебные события . Компоненты могут подписаться на события службы. Например, два компонента sibling могут подписаться на одно и то же событие службы и ответить, изменив их соответствующие модели. Подробнее об этом ниже.

Как я могу связываться между корневым компонентом и компонентом, вложенным в несколько уровней?

  1. Общая модель приложения : модель приложения может быть передана из корневого компонента до глубоко вложенных подкомпонентов с помощью привязок @Input (). Изменения модели от любого компонента будут автоматически распространяться на все компоненты, которые используют одну и ту же модель.
  2. Служебные события . Вы также можете переместить EventEmitter на общую услугу, которая позволяет любому компоненту вводить услугу и подписываться на событие. Таким образом, корневой компонент может вызвать метод службы (обычно мутирующий модель), который, в свою очередь, испускает событие. Несколько слоев вниз, компонент grand-child, который также ввел услугу и подписался на одно и то же событие, может справиться с этим. Любой обработчик событий, который изменяет общую модель приложения, будет автоматически распространяться на все компоненты, зависящие от него. Вероятно, это самый близкий эквивалент $scope.broadcast() от Angular 1. Следующий раздел описывает эту идею более подробно.

Пример наблюдаемой службы, которая использует служебные события для распространения изменений

Ниже приведен пример наблюдаемой службы, которая использует события службы для распространения изменений. Когда добавляется TodoItem, служба выдает событие, уведомляющее своих абонентов.

 export class TodoItem { constructor(public name: string, public done: boolean) { } } export class TodoService { public itemAdded$: EventEmitter; 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: ` 
  • {{ item.name }}

Add Item ` }) export class TriggeringComponent{ private model: TodoItem[]; constructor(private todoService: TodoService) { this.model = todoService.list(); } add(value: string) { this.todoService.add(new TodoItem(value, false)); } }

Ссылка: обнаружение изменения в угловом

Следующий код в качестве примера замены для $ scope.emit () или $ scope.broadcast () в Angular 2 с использованием общей службы для обработки событий.

 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)

Пример плунжера: служба сообщений

 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(); 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: Subscription; 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: Subscription; 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(); } } 

Метод subscribe для MessageService возвращает объект Subscription rxjs, который может быть отписано так:

 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

Пример плунжера: служба сообщений

НЕ используйте EventEmitter для вашего служебного общения.

Вы должны использовать один из типов Observable. Мне лично нравится BehaviorSubject.

Простой пример:

Вы можете передать начальное состояние, здесь я пропускаю нуль

let subject = new BehaviorSubject (null);

Когда вы хотите обновить тему

subject.next (MyObject)

Наблюдайте за любыми службами или компонентами и действуйте, когда они получают новые обновления.

subject.subscribe (this.YOURMETHOD);

Вот еще информация. ,

Вы можете использовать EventEmitter или наблюдаемые для создания службы eventbus, которую вы регистрируете с помощью DI. Каждый компонент, который хочет участвовать, просто запрашивает службу как параметр конструктора и испускает и / или подписывается на события.

Смотрите также

Я создал образец pub-sub здесь:

http://www.syntaxsuccess.com/viewarticle/pub-sub-in-angular-2.0

Идея состоит в том, чтобы использовать объекты RxJs для подключения Observer и Observables в качестве общего решения для испускания и подписки на пользовательские события. В моем примере я использую объект клиента для демонстрационных целей

 this.pubSubService.Stream.emit(customer); this.pubSubService.Stream.subscribe(customer => this.processCustomer(customer)); 

Вот также живая демонстрация: http://www.syntaxsuccess.com/angular-2-samples/#/demo/pub-sub

Мой любимый способ – это использовать субъект поведения или излучатель событий (почти то же самое) в моей службе для управления всем моим подкомпонентом.

Используя угловые cli, запустите ng gs для создания нового сервиса, затем используйте BehaviorSubject или EventEmitter

 export Class myService { #all the stuff that must exist myString: string[] = []; contactChange : BehaviorSubject = 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 } } 

Мы внедрили ngModelChange наблюдаемую директиву, которая отправляет все изменения модели через излучатель событий, который вы создаете в своем собственном компоненте. Вам просто нужно связать свой эмиттер событий с директивой.

См .: https://github.com/atomicbits/angular2-modelchangeobservable

В html свяжите свой эмитент событий (countryChanged в этом примере):

  

В своем машинописном компоненте выполните некоторые асинхронные операции с EventEmitter:

 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[] = [] countryChanged:EventEmitter = new EventEmitter() 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 

использовать:

 export class  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"); 

Служебные события. Компоненты могут подписаться на события службы. Например, два компонента sibling могут подписаться на одно и то же событие службы и ответить, изменив их соответствующие модели. Подробнее об этом ниже.

Но обязательно отпишитесь на это, чтобы уничтожить родительский компонент.

  • Угловой массив объектов для изменения данных
  • Как избежать импорта с очень длинными относительными путями в Angular 2?
  • Каков правильный способ обмена результатами сетевого звонка с угловым Http в RxJs 5?
  • Как обмениваться услугой между двумя модулями - @NgModule в угловом не между компонентами?
  • Angular 2 аннотация @ViewChild возвращает неопределенные
  • Как выбрать элемент в шаблоне компонента?
  • Угловой - общий сервис между компонентами не работает
  • Цепочка RxJS Наблюдаемые данные http в Angular2 с использованием TypeScript
  • Angular2: Как загрузить данные перед рендерингом компонента?
  • Общий валидатор почты в Angular2
  • Что эквивалентно ngShow и ngHide в Angular?
  • Interesting Posts

    Итерация по интерфейсу

    Объяснение объяснения Java Event-Dispatching

    Как передать данные из дочернего компонента в родителя в ReactJS?

    Внешняя сортировка строк, ограниченная памятью, с объединенными и подсчитанными дубликатами на критическом сервере (миллиарды имен файлов)

    Любой более быстрый способ копирования массивов в C #?

    Насколько безопасна клавиатура Bluetooth от Apple?

    Поиск того, какие банки содержат файл

    Почему IE9 показывает только черную страницу?

    Android-сервис убит

    Нет ListBox.SelectionMode = «Нет», есть ли другой способ отключить выбор в списке?

    Что такое C # аналог C ++ std :: pair?

    Можно ли каким-либо образом сделать панель подключения «труднее» отображать с помощью клиента служб терминалов Microsoft?

    Передача lambda в качестве указателя функции

    Как найти все перестановки (с повторением) в MATLAB?

    Что такое .dex-файлы в Android?

    Давайте будем гением компьютера.