[解決済み】Delegation: AngularのEventEmitterまたはObservable
質問
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に更新しました。 を使用する代わりに、次のいずれかを使用します。
- コメントで @Abdulrahman が推奨している BehaviorSubject、または
- コメントで @Jason Goemaat が推奨する ReplaySubject。
A
件名
はObservableであり、(つまり
subscribe()
を呼び出すことができます)。
next()
を実行し、新しい値を生成します。) この特徴を利用する。 Subjectは多くのObserversに値をマルチキャストすることができます。 私たちはこの機能を利用していません(Observerは1つだけです)。
ビヘイビアサブジェクト はSubjectの変種です。 これは、quot;現在の値"という概念を持っています。 ObservingComponentを作成すると、自動的にBehaviorSubjectから現在のナビゲーションアイテムの値が取得されます。
以下のコードと プランカー はBehaviorSubjectを使用しています。
リプレイサブジェクト
はSubjectの別の変形です。実際に値が生成されるまで待ちたい場合は
ReplaySubject(1)
. BehaviorSubjectは初期値(すぐに提供される)を必要としますが、ReplaySubjectはそうではありません。 ReplaySubjectは常に最新の値を提供しますが、必須の初期値を持っていないため、サービスは最初の値を返す前に何らかの非同期処理を行うことができます。 しかし、初期値を必要としないため、サービスは最初の値を返す前に何らかの非同期処理を行うことができます。もし、1つの値だけが欲しいのであれば
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);
}
}
Observableを使用したオリジナルの回答です。 (BehaviorSubjectを使うよりも多くのコードとロジックが必要なので、お勧めしませんが、参考になるかもしれません)
では、Observableを使った実装を紹介します。
イベントエミッターの代わりに
. 私の EventEmitter の実装とは異なり、この実装では、現在選択されている
navItem
このため、Observation コンポーネントが作成されたときに、APIコール
navItem()
で変更されたことが通知されます。
navChange$
Observableです。
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);
}
}
も参照してください。
Component Interaction Cookbook の例
を使用しています。
Subject
をobservableに加えて使用します。 この例では、親と子のコミュニケーションですが、関連性のないコンポーネントにも同じ手法が適用できます。
関連
-
[解決済み] EventEmitter のメモリリークの可能性が検出された
-
[解決済み] Angular 2で簡単なアコーディオンを作成するにはどうすればよいですか?
-
[解決済み] Angular2の$document.ready()に相当します。
-
[解決済み] モジュール 'AppModule' によってインポートされた予期しないディレクティブ 'LoginComponent' があります。NgModuleアノテーションを追加してください。
-
[解決済み] Angular 4 - "BrowserAnimationsModule "または "NoopAnimationsModule "のいずれかをアプリケーションに組み込んでください。
-
[解決済み] Angular HTMLバインディング
-
[解決済み] Angular:*ngClassを使った条件付きクラス
-
[解決済み] BehaviorSubjectとObservableの違い?
-
[解決済み] Angular/RxJS `Subscription` からいつ退会すればいいのか?
-
[解決済み] モジュール "@angular-devkit/build-angular" が見つかりませんでした。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] node_modules が空になったので、`npm install`を実行する必要があるかもしれない。
-
[解決済み] Angular EXCEPTION: Http用のプロバイダがありません。
-
[解決済み] Visual Code で未定義のプロパティ 'thisCompilation' を読み取ることができません。
-
[解決済み] ZoneAwarePromiseとは
-
[解決済み] Angularアプリのシンタックスエラー。予期しないトークン <
-
[解決済み] Angular 6でmouseoverとmouseoutを使用する方法
-
[解決済み】EventEmitterの正しい使い方とは?
-
[解決済み】Angularのグローバルイベント
-
[解決済み] Angular 2 / Typescriptでグローバル変数を宣言するにはどうすればよいですか?[クローズド]
-
[解決済み] Angular 2 ServiceからObservableを作成し返す