Usiłuję zaimplementować coś w rodzaju wzoru delegowania w Angular. Gdy użytkownik kliknie „a” nav-item
, chciałbym wywołać funkcję, która następnie emituje zdarzenie, które z kolei powinno być obsługiwane przez inny komponent nasłuchujący zdarzenia.
Oto scenariusz: Mam Navigation
komponent:
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)
}
}
Oto element obserwacyjny:
export class ObservingComponent {
// How do I observe the event ?
// <----------Observe/Register Event ?-------->
public selectedNavItem(item: number) {
console.log('item index changed!');
}
}
Kluczowe pytanie brzmi: jak sprawić, by obserwujący obserwował obserwowane zdarzenie?
Odpowiedzi:
Aktualizacja 27.06.2016: zamiast korzystać z Obserwowalnych, użyj jednego z nich
Dotyczy to zarówno Obserwowalne (tak, możemy
subscribe()
do niego) i obserwatora (tak możemy nazwaćnext()
go, aby emitować nową wartość). Wykorzystujemy tę funkcję. Temat pozwala wartościom być multiemisją dla wielu obserwatorów. Nie wykorzystujemy tej funkcji (mamy tylko jednego Obserwatora).BehaviorSubject to odmiana podmiotu. Ma pojęcie „bieżącej wartości”. Wykorzystujemy to: za każdym razem, gdy tworzymy ObservingComponent, automatycznie pobiera bieżącą wartość elementu nawigacyjnego z BehaviorSubject.
Poniższy kod i plunker używają BehaviorSubject.
ReplaySubject to kolejny wariant podmiotu. Jeśli chcesz poczekać, aż wartość zostanie faktycznie wygenerowana, użyj
ReplaySubject(1)
. Podczas gdy BehaviorSubject wymaga wartości początkowej (która zostanie podana natychmiast), ReplaySubject nie. ReplaySubject zawsze zapewnia najnowszą wartość, ale ponieważ nie ma wymaganej wartości początkowej, usługa może wykonać operację asynchroniczną przed zwróceniem swojej pierwszej wartości. Nadal będzie uruchamiany natychmiast po kolejnych połączeniach o najnowszej wartości. Jeśli chcesz tylko jedną wartość, skorzystajfirst()
z subskrypcji. Nie musisz rezygnować z subskrypcji, jeśli korzystaszfirst()
.Plunker
Oryginalna odpowiedź, która wykorzystuje Observable: (wymaga więcej kodu i logiki niż użycie BehaviorSubject, więc nie polecam, ale może być pouczająca)
Oto implementacja korzystająca z Observable zamiast EventEmitter . W przeciwieństwie do mojej implementacji EventEmitter, ta implementacja przechowuje również aktualnie wybrany
navItem
w usłudze, dzięki czemu, gdy tworzony jest komponent obserwacyjny, może on pobierać bieżącą wartość za pośrednictwem wywołania APInavItem()
, a następnie być powiadamiany o zmianach za pośrednictwemnavChange$
Obserwowalnego.Plunker
Zobacz także przykład książki kucharskiej interakcji między komponentami , w której
Subject
oprócz obserwowalności używa się dodatkowo. Chociaż przykładem jest „komunikacja rodziców i dzieci”, ta sama technika ma zastosowanie do niepowiązanych komponentów.źródło
EventEmitter
dowolnym miejscu, z wyjątkiem wyników. Obecnie przepisują samouczki (komunikacja AFAIR z serwerem), aby nie zachęcać do tej praktyki._observer
obiekt usługi nie jest przynajmniej inicjowany w momenciengOnInit()
wywołania komponentu Nawigacji.EventEmitter
ponieważ jest „gorący”, co oznacza, że jest już „udostępniony”, ma na celu zapisanie bieżącej wartości, a na koniec implementuje zarówno Observable, jak i Observer, co pozwoli Ci zaoszczędzić co najmniej pięć wierszy kodu i dwie właściwościsubscribe()
, więc nie może wykryć zmian, które można zaobserwować. Zwykle jest uruchamiane jakieś zdarzenie asynchroniczne (w moim przykładowym kodzie są to zdarzenia kliknięcia przycisku), a powiązane wywołanie zwrotne wywoła next () na obserwowalnym. Wykrywanie zmian działa jednak z powodu zdarzenia asynchronicznego, a nie z powodu zauważalnej zmiany. Zobacz także komentarze Güntera: stackoverflow.com/a/36846501/215945ReplaySubject(1)
.BehaviorSubject
Wymaga początkowej wartości, które zostaną dostarczone natychmiast.ReplaySubject(1)
Zawsze dostarczy najnowszej wartości, ale nie ma początkową wartość wymagana więc usługa może zrobić kilka operacji asynchronicznej przed wpuszczeniem go na pierwszą wartość, ale natychmiast ogień na kolejnych połączeń z ostatniej wartości. Jeśli interesuje Cię tylko jedna wartość, której możesz użyćfirst()
w subskrypcji i nie musisz rezygnować z subskrypcji na końcu, ponieważ to się skończy.Najświeższe informacje: Dodałem inną odpowiedź, która używa Observable, a nie EventEmitter. Polecam tę odpowiedź zamiast tej. W rzeczywistości używanie EventEmittera w usłudze jest złą praktyką .
Oryginalna odpowiedź: (nie rób tego)
Umieść EventEmitter w usłudze, która pozwala ObservingComponent na bezpośrednie subskrybowanie (i anulowanie subskrypcji) zdarzenia:Jeśli spróbujesz Plunker, w tym podejściu nie podoba mi się kilka rzeczy:
subscribe()
właściwośćthis
została ustawiona po wywołaniu wywołania zwrotnegoAktualizacja: Alternatywą, która rozwiązuje 2. punkt, jest
navchange
observingComponent bezpośrednio subskrybujący właściwość EventEmitter:Jeśli subskrybujemy bezpośrednio, nie potrzebowalibyśmy tej
subscribe()
metody na NavService.Aby NavService było nieco bardziej enkapsulowane, możesz dodać
getNavChangeEmitter()
metodę i użyć jej:źródło
this.subscription = this.navService.subscribe(() => this.selectedNavItem());
i po zasubskrybowaniu:return this.navchange.subscribe(callback);
Jeśli ktoś chce zastosować programowanie bardziej zorientowane na reakcję, zdecydowanie pojawia się koncepcja „Wszystko jest strumieniem”, a zatem należy używać Observables do radzenia sobie z tymi strumieniami tak często, jak to możliwe.
źródło
Możesz użyć:
BehaviorSubject jest rodzajem podmiotu, podmiot jest szczególnym rodzajem obserwowalnego, który może działać jako obserwowalny, a obserwator można subskrybować wiadomości jak każdy inny obserwowalny, a po subskrypcji zwraca ostatnią wartość podmiotu emitowaną przez obserwowalne źródło:
Korzyść: brak relacji, takich jak relacja rodzic-dziecko, wymagana do przekazywania danych między komponentami.
SERWIS NAV
KOMPONENT NAWIGACYJNY
ELEMENT OBSERWUJĄCY
Drugie podejście to
Event Delegation in upward direction child -> parent
np. Odpowiedź udzielona przez @Ashish Sharma.
źródło
Musisz użyć komponentu Nawigacja w szablonie ObservingComponent (nie zapomnij dodać selektora do komponentu Nawigacja .. np. Komponent nawigacyjny)
I zaimplementuj onNavGhange () w ObservingComponent
Ostatnia rzecz ... nie potrzebujesz atrybutu events w @Componennt
źródło
nav-item
ale chcę po prostu wyemitować zdarzenie, które inni mogą obserwować.możesz użyć BehaviourSubject zgodnie z powyższym opisem lub istnieje jeszcze jeden sposób:
możesz obsługiwać EventEmitter w następujący sposób: najpierw dodaj selektor
Teraz możesz poradzić sobie z tym zdarzeniem, na przykład załóżmy, że observer.component.html jest widokiem komponentu Observer
następnie w ObservingComponent.ts
źródło
Znalazłem inne rozwiązanie dla tej sprawy bez korzystania z usług Reactivex ani. Naprawdę uwielbiam interfejs API rxjx, jednak myślę, że najlepiej działa przy rozwiązywaniu funkcji asynchronicznych i / lub złożonych. Używając go w ten sposób, to całkiem mnie przerosło.
Myślę, że szukasz audycji. Tylko to. I znalazłem to rozwiązanie:
To jest w pełni działający przykład: https://plnkr.co/edit/xGVuFBOpk2GP0pRBImsE
źródło