Я пытаюсь реализовать что-то вроде шаблона делегирования в Angular. Когда пользователь нажимает на nav-item
, я хотел бы вызвать функцию, которая затем генерирует событие, которое, в свою очередь, должно обрабатываться другим компонентом, прослушивающим событие.
Вот сценарий: у меня есть Navigation
компонент:
import {Component, Output, EventEmitter} from 'angular2/core';
@Component({
// other properties left out for brevity
events : ['navchange'],
template:`
<div class="nav-item" (click)="selectedNavItem(1)"></div>
`
})
export class Navigation {
@Output() navchange: EventEmitter<number> = new EventEmitter();
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this.navchange.emit(item)
}
}
Вот компонент наблюдения:
export class ObservingComponent {
// How do I observe the event ?
// <----------Observe/Register Event ?-------->
public selectedNavItem(item: number) {
console.log('item index changed!');
}
}
Ключевой вопрос заключается в том, как заставить компонент наблюдения наблюдать за рассматриваемым событием?
Ответы:
Обновление 2016-06-27: вместо использования Observables используйте либо
Предмет является как Наблюдаемые (так что мы можем
subscribe()
к нему) и наблюдатель (так что мы можем назватьnext()
на ней , чтобы излучать новое значение). Мы используем эту функцию. Предмет позволяет значениям быть многоадресными для многих наблюдателей. Мы не используем эту функцию (у нас есть только один наблюдатель).BehaviorSubject является вариантом Subject. Имеет понятие «текущая стоимость». Мы используем это: всякий раз, когда мы создаем ObservingComponent, он автоматически получает текущее значение элемента навигации из BehaviorSubject.
Код ниже и плункер используют BehaviorSubject.
ReplaySubject - это еще один вариант Subject. Если вы хотите подождать, пока значение не будет получено, используйте
ReplaySubject(1)
. Принимая во внимание, что BehaviorSubject требует начального значения (которое будет предоставлено немедленно), ReplaySubject не делает. ReplaySubject всегда будет предоставлять самое последнее значение, но поскольку у него нет требуемого начального значения, служба может выполнить некоторую асинхронную операцию, прежде чем вернуть свое первое значение. Он все равно будет срабатывать немедленно при последующих вызовах с самым последним значением. Если вам нужно только одно значение, используйтеfirst()
подписку. Вам не нужно отписываться, если вы используетеfirst()
.Plunker
Оригинальный ответ, который использует Observable: (он требует больше кода и логики, чем использование BehaviorSubject, поэтому я не рекомендую его, но это может быть поучительно)
Итак, вот реализация, которая использует Observable вместо EventEmitter . В отличие от моей реализации EventEmitter, эта реализация также сохраняет
navItem
текущий выбранный в сервисе, так что когда создается компонент наблюдения, он может получить текущее значение с помощью вызова APInavItem()
, а затем получать уведомления об изменениях черезnavChange$
Observable.Plunker
См. Также пример Поваренной книги взаимодействия компонентов , в которой
Subject
в дополнение к наблюдаемым используется. Хотя примером является «общение между родителями и детьми», тот же метод применим для несвязанных компонентов.источник
EventEmitter
где-либо, кроме выходов. В настоящее время они переписывают учебные пособия (сервер связи AFAIR), чтобы не поощрять эту практику._observer
что объект службы по меньшей мере не инициализируется во времяngOnInit()
вызова компонента навигации.EventEmitter
потому что он «горячий», то есть он уже «общий», он предназначен для сохранения текущего значения и, наконец, реализует как Observable, так и Observer, которые сохранят вам как минимум пять строк кода и два свойстваsubscribe()
, поэтому не может обнаружить, когда наблюдаемые изменения изменяются. Обычно, возникает некоторое асинхронное событие (в моем примере кода это события нажатия кнопки), и связанный с ним обратный вызов будет вызывать next () для наблюдаемой. Но обнаружение изменений происходит из-за асинхронного события, а не из-за наблюдаемого изменения. См. Также комментарии Гюнтера: stackoverflow.com/a/36846501/215945ReplaySubject(1)
. ABehaviorSubject
требует начального значения, которое будет предоставлено немедленно.ReplaySubject(1)
Всегда будет обеспечивать самое последнее значение, но не имеет начальное значение , необходимое , чтобы обслуживание может сделать какую - то операцию асинхронной перед его возвращением в первое значение, но все - таки срабатывает сразу при последующих вызовах с последним значением. Если вас интересует только одно значение, которое вы можете использоватьfirst()
в подписке, и вам не нужно отписываться в конце, потому что оно будет выполнено.Последние новости: я добавил еще один ответ, который использует Observable, а не EventEmitter. Я рекомендую ответить на этот вопрос. И на самом деле, использование EventEmitter в сервисе - плохая практика .
Оригинальный ответ: (не делай этого)
Поместите EventEmitter в сервис, который позволяет ObservingComponent напрямую подписываться (и отписываться) на событие:Если вы попробуете Plunker, есть несколько вещей, которые мне не нравятся в этом подходе:
subscribe()
так, чтобыthis
при вызове вызывался правильныйОбновление: альтернатива, которая решает 2-ую пулю, состоит в том, чтобы ObservingComponent непосредственно подписывался на
navchange
свойство EventEmitter:Если мы подпишемся напрямую, нам не понадобится
subscribe()
метод NavService.Чтобы сделать NavService немного более инкапсулированным, вы можете добавить
getNavChangeEmitter()
метод и использовать его:источник
this.subscription = this.navService.subscribe(() => this.selectedNavItem());
и на подписку:return this.navchange.subscribe(callback);
Если кто-то хочет следовать более реактивному стилю программирования, тогда определенно возникает концепция «Все есть поток», и, следовательно, используйте Observables для работы с этими потоками как можно чаще.
источник
Вы можете использовать либо:
BehaviorSubject - это тип субъекта, субъект - это особый тип наблюдаемого, который может выступать в качестве наблюдаемого, и наблюдатель, которого вы можете подписать на сообщения, как и любое другое наблюдаемое, и после подписки возвращает последнее значение субъекта, излученное наблюдаемым источником:
Преимущество: для передачи данных между компонентами не требуется таких отношений, как отношения родитель-потомок.
НАВ СЕРВИС
НАВИГАЦИОННЫЙ КОМПОНЕНТ
НАБЛЮДАЮЩИЙ КОМПОНЕНТ
Второй подход
Event Delegation in upward direction child -> parent
например, ответ от @Ashish Sharma.
источник
Вам необходимо использовать компонент Navigation в шаблоне ObservingComponent (не забудьте добавить селектор в компонент Navigation. Компонент для навигации, например)
И реализовать onNavGhange () в ObservingComponent
И последнее ... вам не нужен атрибут events в @Componennt
источник
nav-item
но я просто хочу выпустить событие, которое могут наблюдать другие.Вы можете использовать BehaviourSubject, как описано выше, или есть еще один способ:
вы можете обрабатывать EventEmitter следующим образом: сначала добавьте селектор
Теперь вы можете обработать это событие, например , предположим, что наблюдающий.component.html является представлением компонента Observer.
затем в ObservingComponent.ts
источник
Я нашел другое решение для этого случая без использования Reactivex ни услуги. Я действительно люблю API rxjx, но думаю, что он лучше всего подходит для разрешения асинхронных и / или сложных функций. Используя это таким образом, это довольно превзошло меня.
Я думаю, что вы ищете для трансляции. Только то. И я нашел это решение:
Это полный рабочий пример: https://plnkr.co/edit/xGVuFBOpk2GP0pRBImsE
источник