위임:이벤트 이미터 또는 각도로 관찰 가능
저는 Angular에서 위임 패턴과 같은 것을 구현하려고 합니다.▁on▁a를 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 업데이트: 관찰 가능 항목을 사용하는 대신 다음 중 하나를 사용합니다.
- @Abdulrahman이 댓글에서 추천한 행동 주체, 또는
- @Jason Goemat이 코멘트에서 추천한 ReplaySubject
환자는 둘 다 관측 가능합니다(따라서 우리는 할 수 있습니다.subscribe()
그것에)와 옵저버(우리가 부를 수 있도록).next()
새로운 값을 방출하기 위해).이 기능을 이용합니다.제목을 사용하면 값을 여러 관찰자에게 멀티캐스트할 수 있습니다.이 기능은 이용하지 않습니다(옵저버는 한 명뿐입니다).
BehaviorSubject는 제목의 변형입니다.그것은 "현재 값"이라는 개념을 가지고 있습니다.우리는 이것을 이용합니다. 관찰 구성 요소를 만들 때마다 BehaviorSubject에서 현재 탐색 항목 값을 자동으로 가져옵니다.
아래 코드와 플런커는 BehaviorSubject를 사용합니다.
ReplaySubject는 Subject의 다른 변형입니다.값이 실제로 생성될 때까지 기다리려면 다음을 사용합니다.ReplaySubject(1)
BehaviorSubject에는 초기 값(즉시 제공됨)이 필요하지만 ReplaySubject에는 그렇지 않습니다.ReplaySubject는 항상 최신 값을 제공하지만 필수 초기 값이 없기 때문에 서비스는 첫 번째 값을 반환하기 전에 일부 비동기 작업을 수행할 수 있습니다.가장 최근의 값을 가진 후속 호출에 대해서도 즉시 실행됩니다.값만 에는 하의값원경우는하를 합니다.first()
기부금으로를 사용하는 경우 구독을 취소할 필요가 없습니다.first()
.
import {Injectable} from '@angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
@Injectable()
export class NavService {
// Observable navItem source
private _navItemSource = new BehaviorSubject<number>(0);
// Observable navItem stream
navItem$ = this._navItemSource.asObservable();
// service command
changeNav(number) {
this._navItemSource.next(number);
}
}
import {Component} from '@angular/core';
import {NavService} from './nav.service';
import {Subscription} from 'rxjs/Subscription';
@Component({
selector: 'obs-comp',
template: `obs component, item: {{item}}`
})
export class ObservingComponent {
item: number;
subscription:Subscription;
constructor(private _navService:NavService) {}
ngOnInit() {
this.subscription = this._navService.navItem$
.subscribe(item => this.item = item)
}
ngOnDestroy() {
// prevent memory leak when component is destroyed
this.subscription.unsubscribe();
}
}
@Component({
selector: 'my-nav',
template:`
<div class="nav-item" (click)="selectedNavItem(1)">nav 1 (click me)</div>
<div class="nav-item" (click)="selectedNavItem(2)">nav 2 (click me)</div>`
})
export class Navigation {
item = 1;
constructor(private _navService:NavService) {}
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this._navService.changeNav(item);
}
}
관찰 가능한 항목을 사용하는 원래 답변: (BehaviorSubject를 사용하는 것보다 더 많은 코드와 논리가 필요하므로 권장하지 않지만 유용할 수 있습니다.)
여기 이벤트 이미터 대신 관찰 가능한 것을 사용하는 구현이 있습니다.내 EventEmitter 구현과 달리 이 구현은 현재 선택된 항목도 저장합니다.navItem
서비스에서 관찰 구성요소가 생성될 때 API 호출을 통해 현재 값을 검색할 수 있습니다.navItem()
그런 다음 변경 사항을 통해 통보받습니다.navChange$
관찰 가능한.
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/share';
import {Observer} from 'rxjs/Observer';
export class NavService {
private _navItem = 0;
navChange$: Observable<number>;
private _observer: Observer;
constructor() {
this.navChange$ = new Observable(observer =>
this._observer = observer).share();
// share() allows multiple subscribers
}
changeNav(number) {
this._navItem = number;
this._observer.next(number);
}
navItem() {
return this._navItem;
}
}
@Component({
selector: 'obs-comp',
template: `obs component, item: {{item}}`
})
export class ObservingComponent {
item: number;
subscription: any;
constructor(private _navService:NavService) {}
ngOnInit() {
this.item = this._navService.navItem();
this.subscription = this._navService.navChange$.subscribe(
item => this.selectedNavItem(item));
}
selectedNavItem(item: number) {
this.item = item;
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@Component({
selector: 'my-nav',
template:`
<div class="nav-item" (click)="selectedNavItem(1)">nav 1 (click me)</div>
<div class="nav-item" (click)="selectedNavItem(2)">nav 2 (click me)</div>
`,
})
export class Navigation {
item:number;
constructor(private _navService:NavService) {}
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this._navService.changeNav(item);
}
}
다음을 사용하는 구성요소 상호 작용 요리책 예제도 참조하십시오.Subject
관측할 수 있는 것 외에예를 들어 "부모 및 자녀 통신"이 있지만 관련이 없는 구성요소에도 동일한 기법이 적용됩니다.
속보:이벤트 이미터가 아닌 관찰 가능한 항목을 사용하는 다른 답변을 추가했습니다.저는 이 대답보다 그 대답을 추천합니다.실제로 서비스에서 이벤트 이미터를 사용하는 것은 좋지 않은 관행입니다.
원래 답변: (이 작업을 수행하지 않음)
이벤트 이미터를 서비스에 배치하여 감시 구성 요소가 이벤트를 직접 구독(및 구독 취소)할 수 있도록 합니다. :
import {EventEmitter} from 'angular2/core';
export class NavService {
navchange: EventEmitter<number> = new EventEmitter();
constructor() {}
emit(number) {
this.navchange.emit(number);
}
subscribe(component, callback) {
// set 'this' to component when callback is called
return this.navchange.subscribe(data => call.callback(component, data));
}
}
@Component({
selector: 'obs-comp',
template: 'obs component, index: {{index}}'
})
export class ObservingComponent {
item: number;
subscription: any;
constructor(private navService:NavService) {
this.subscription = this.navService.subscribe(this, this.selectedNavItem);
}
selectedNavItem(item: number) {
console.log('item index changed!', item);
this.item = item;
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
@Component({
selector: 'my-nav',
template:`
<div class="nav-item" (click)="selectedNavItem(1)">item 1 (click me)</div>
`,
})
export class Navigation {
constructor(private navService:NavService) {}
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this.navService.emit(item);
}
}
이 방법을 사용해 보면 다음과 같은 몇 가지 방법이 마음에 들지 않습니다.
- 감시 구성 요소가 파괴되면 구독을 취소해야 합니다.
- 는 그 를 는구성요전야합니다해달소를우리에 전달해야 합니다.
subscribe()
적한절이 .this
콜백이 호출될 때 설정됩니다.
두 기호를 수 업데트: ▁the▁to▁subscribe▁update▁directly▁is▁an▁the다component:업▁to▁observing것니▁that데에 가입하는 입니다.navchange
이벤트 이미터 속성:
constructor(private navService:NavService) {
this.subscription = this.navService.navchange.subscribe(data =>
this.selectedNavItem(data));
}
우리가 직접 구독하면, 우리는 필요하지 않을 것입니다.subscribe()
메서드를 선택합니다.
더 하려면 NavService 좀 더 캡 슐 화 하 있 수 습 니 다 할 getNavChangeEmitter()
방법 및 사용:
getNavChangeEmitter() { return this.navchange; } // in NavService
constructor(private navService:NavService) { // in ObservingComponent
this.subscription = this.navService.getNavChangeEmitter().subscribe(data =>
this.selectedNavItem(data));
}
다음 중 하나를 사용할 수 있습니다.
- 행동 주체:
BehaviorSubject는 제목의 한 유형이며, 제목은 관찰 가능한 역할을 하며 다른 관찰 가능한 메시지와 같이 메시지를 구독할 수 있는 관찰 가능한 특수 유형입니다. 구독하면 관찰 가능한 원본에서 내보낸 제목의 마지막 값을 반환합니다.
장점:구성 요소 간에 데이터를 전달하는 데 부모-자녀 관계와 같은 관계가 필요하지 않습니다.
내비게이션 서비스
import {Injectable} from '@angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
@Injectable()
export class NavService {
private navSubject$ = new BehaviorSubject<number>(0);
constructor() { }
// Event New Item Clicked
navItemClicked(navItem: number) {
this.navSubject$.next(number);
}
// Allowing Observer component to subscribe emitted data only
getNavItemClicked$() {
return this.navSubject$.asObservable();
}
}
내비게이션 구성 요소
@Component({
selector: 'navbar-list',
template:`
<ul>
<li><a (click)="navItemClicked(1)">Item-1 Clicked</a></li>
<li><a (click)="navItemClicked(2)">Item-2 Clicked</a></li>
<li><a (click)="navItemClicked(3)">Item-3 Clicked</a></li>
<li><a (click)="navItemClicked(4)">Item-4 Clicked</a></li>
</ul>
})
export class Navigation {
constructor(private navService:NavService) {}
navItemClicked(item: number) {
this.navService.navItemClicked(item);
}
}
구성 요소 관찰
@Component({
selector: 'obs-comp',
template: `obs component, item: {{item}}`
})
export class ObservingComponent {
item: number;
itemClickedSubcription:any
constructor(private navService:NavService) {}
ngOnInit() {
this.itemClickedSubcription = this.navService
.getNavItemClicked$
.subscribe(
item => this.selectedNavItem(item)
);
}
selectedNavItem(item: number) {
this.item = item;
}
ngOnDestroy() {
this.itemClickedSubcription.unsubscribe();
}
}
번째 은 두째번접은법입니다.Event Delegation in upward direction child -> parent
- @Input 및 @Output decorator 사용 부모 구성요소에 데이터 전달 및 자식 알림 부모 구성요소
예: @Ashish Sharma가 제공한 답변.
좀 더 사후 대응적인 방식의 프로그래밍을 따르고 싶다면 "모든 것이 스트림"이라는 개념이 확실히 이해되기 때문에 관찰 가능한 스트림을 가능한 한 자주 사용하십시오.
위에서 설명한 대로 BehaviorSubject를 사용할 수도 있고 다른 방법이 있습니다.
이벤트 이미터를 다음과 같이 처리할 수 있습니다. 먼저 선택기를 추가합니다.
import {Component, Output, EventEmitter} from 'angular2/core';
@Component({
// other properties left out for brevity
selector: 'app-nav-component', //declaring selector
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)
}
}
이제 당신은 다음과 같이 이 이벤트를 처리할 수 있습니다. Observer.component.html이 Observer 구성 요소의 뷰라고 가정합니다.
<app-nav-component (navchange)="recieveIdFromNav($event)"></app-nav-component>
그런 다음 Observating Component.ts에 표시됩니다.
export class ObservingComponent {
//method to recieve the value from nav component
public recieveIdFromNav(id: number) {
console.log('here is the id sent from nav component ', id);
}
}
ObservatingComponent(관찰 구성 요소) 템플릿에서 Navigation 구성 요소를 사용해야 합니다(Navigation 구성 요소에 선택기를 추가하는 것을 잊지 마십시오).탐색 구성 요소(예: )
<navigation-component (navchange)='onNavGhange($event)'></navigation-component>
그리고 관찰 구성 요소의 NavHange()에 구현합니다.
onNavGhange(event) {
console.log(event);
}
마지막으로..@Component에 이벤트 속성이 필요하지 않습니다.
events : ['navchange'],
저는 두 서비스 모두 Reactivex를 사용하지 않고 이 사례에 대한 다른 솔루션을 찾았습니다.저는 사실 rxjx API를 좋아하지만 비동기 및/또는 복잡한 기능을 해결할 때 가장 적합하다고 생각합니다.그것을 그런 식으로 사용하는 것은 저에게는 꽤 지나쳤습니다.
당신이 찾고 있는 것은 방송을 위한 것이라고 생각합니다.바로 그거.그리고 저는 다음과 같은 해결책을 찾았습니다.
<app>
<app-nav (selectedTab)="onSelectedTab($event)"></app-nav>
// This component bellow wants to know when a tab is selected
// broadcast here is a property of app component
<app-interested [broadcast]="broadcast"></app-interested>
</app>
@Component class App {
broadcast: EventEmitter<tab>;
constructor() {
this.broadcast = new EventEmitter<tab>();
}
onSelectedTab(tab) {
this.broadcast.emit(tab)
}
}
@Component class AppInterestedComponent implements OnInit {
broadcast: EventEmitter<Tab>();
doSomethingWhenTab(tab){
...
}
ngOnInit() {
this.broadcast.subscribe((tab) => this.doSomethingWhenTab(tab))
}
}
다음은 완전한 작동 예입니다. https://plnkr.co/edit/xGVuFBOpk2GP0pRBImsE
언급URL : https://stackoverflow.com/questions/34376854/delegation-eventemitter-or-observable-in-angular
'it-source' 카테고리의 다른 글
보안.예외 권한 거부: 제공자 com.google.android.gms를 엽니다.표현형, 표현형. 기호형.구성 공급자 (0) | 2023.06.06 |
---|---|
Firebase 스토리지 이미지 저장 및 검색 방법 (0) | 2023.06.06 |
Mysql JSON 업데이트 키 값 (0) | 2023.06.06 |
변수를 사용하여 열 이름을 지정하는 방법 ggplot (0) | 2023.06.06 |
Android 그리기 가능 디렉토리에 하위 디렉토리를 포함할 수 있습니까? (0) | 2023.06.06 |