ユーザーがドロップダウン以外の場所をクリックしたときにログインメニューのドロップダウンを閉じたいのですが、Angular2とAngular2の "アプローチ"でそれを実行したいのですが...
ソリューションを実装しましたが、自信がありません。同じ結果を達成する最も簡単な方法がなければならないと私は思います、あなたが何かアイデアがあれば...議論しましょう:)!
これが私の実装です:
ドロップダウンコンポーネント:
これは私のドロップダウンのコンポーネントです:
- このコンポーネントが可視に設定されるたびに(たとえば、ユーザーがボタンをクリックしてそれを表示すると)、SubjectsService内に格納された「グローバル」なrxjsサブジェクトuserMenuにサブスクライブします。
- そして、それが非表示になるたびに、この件名の購読を解除します。
- このコンポーネントのテンプレート内の任意の場所をクリックするたびに、onClick()メソッドがトリガーされます。これにより、上部(およびアプリケーションコンポーネント)へのイベントバブリングが停止します。
これがコードです
export class UserMenuComponent {
_isVisible: boolean = false;
_subscriptions: Subscription<any> = null;
constructor(public subjects: SubjectsService) {
}
onClick(event) {
event.stopPropagation();
}
set isVisible(v) {
if( v ){
setTimeout( () => {
this._subscriptions = this.subjects.userMenu.subscribe((e) => {
this.isVisible = false;
})
}, 0);
} else {
this._subscriptions.unsubscribe();
}
this._isVisible = v;
}
get isVisible() {
return this._isVisible;
}
}
アプリケーションコンポーネント:
一方、アプリケーションコンポーネント(ドロップダウンコンポーネントの親)があります。
- このコンポーネントは、すべてのクリックイベントをキャッチし、同じrxjsサブジェクト(userMenu)で発行します
これがコードです:
export class AppComponent {
constructor( public subjects: SubjectsService) {
document.addEventListener('click', () => this.onClick());
}
onClick( ) {
this.subjects.userMenu.next({});
}
}
何が私を困らせましたか:
- これらのコンポーネント間のコネクタとして機能するグローバルなサブジェクトを使用するという考えには、あまり慣れていません。
- setTimeout:ここでは、ユーザーがドロップダウンを表示するボタンをクリックした場合そう起こるものですので、これが必要とされています。
- ユーザーがボタン(ドロップダウンコンポーネントの一部ではない)をクリックして、ドロップダウンを表示します。
- ドロップダウンが表示され、すぐにuserMenuサブジェクトにサブスクライブします。
- クリックイベントがアプリコンポーネントまでバブルアップしてキャッチされる
- アプリケーションコンポーネントは、userMenuサブジェクトでイベントを発行します
- ドロップダウンコンポーネントは、userMenuでこのアクションをキャッチし、ドロップダウンを非表示にします。
- 最後に、ドロップダウンは表示されません。
この設定されたタイムアウトにより、現在のJavaScriptコードターンの最後までサブスクリプションが遅延し、問題が解決しますが、私の意見では非常にエレガントな方法です。
よりクリーンで、より良い、よりスマート、より高速、またはより強力なソリューションをご存知の場合は、私にお知らせください:)!