ネイティブの_<button>
_要素をいくつかの追加機能でラップするAngularコンポーネントを作成しています。ボタンが無効になっていて同じものを複製したい場合、ボタンはクリックイベントを起動しません機能性、すなわち、与えられた:
_<my-button (click)="onClick()" [isDisabled]="true">Save</my-button>
_
_my-button
_がonClick()
が呼び出されるのを防ぐ方法はありますか?
Angularこの方法でホストクリックイベントをリッスンし、イベントのpropagationを停止できます。
_//Inside my-button component
@HostListener('click', ['$event'])
onHostClick(event: MouseEvent) {
event.stopPropagation();
}
_
これにより、イベントが先祖要素にバブリングするのを防ぎますが、組み込みの_(click)
_出力が同じHost要素で発生するのを停止しません。
これを達成する方法はありますか?
編集1:これを解決する方法は、「onClick」と呼ばれる別の出力を使用することです。消費者は「click」ではなく「onClick」を使用することを知っている必要があります。理想的ではありません。
編集2: _<button>
_要素で発生したクリックイベントは正常に停止します。しかし、私が持っているようにボタンタグ内に要素を配置すると、それらのターゲットのクリックイベントはホストまで伝播します。うーん、伝播を停止する別の要素でボタンをラップすることができるはずです...
次のことができます。
click
イベントを再定義し、ボタンがクリックされたときにこのイベントを発行しますpointer-events: none
_を設定しますpointer-events: auto
_を設定しますevent.stopPropagation()
を呼び出しますコンポーネント内の他の要素のクリックイベントを処理する必要がある場合は、それらにスタイル属性_pointer-events: auto
_を設定し、クリックイベントハンドラーでevent.stopPropagation()
を呼び出します。
this stackblitz でコードをテストできます。
_import { Component, HostListener, Input, Output, ElementRef, EventEmitter } from '@angular/core';
@Component({
selector: 'my-button',
Host: {
"[style.pointer-events]": "'none'"
},
template: `
<button (click)="onButtonClick($event)" [disabled]="isDisabled" >...</button>
<span (click)="onSpanClick($event)">Span element</span>`,
styles: [`button, span { pointer-events: auto; }`]
})
export class MyCustomComponent {
@Input() public isDisabled: boolean = false;
@Output() public click: EventEmitter<MouseEvent> = new EventEmitter();
onButtonClick(event: MouseEvent) {
event.stopPropagation();
this.click.emit(event);
}
onSpanClick(event: MouseEvent) {
event.stopPropagation();
}
}
_
[〜#〜] update [〜#〜]:
ボタンにはHTMLの子要素(span
、img
など)を含めることができるため、次のCSSスタイルを追加して、クリックが親に伝達されないようにすることができます。
_:Host ::ng-deep button * {
pointer-events: none;
}
_
@ ErikWitkowski for his comment に感謝します。デモについては this stackblitz をご覧ください。
2016年の このgitの問題 でサポートされているように、イベントの発生を防ぐネイティブな方法があるとは思わない:
実行順序は赤字です。同じ要素のイベントが複数のリスナーに伝播される順序は現在定義されていません。これは現在仕様です。
問題は、リスナーに公開されるイベントが実際のDOMイベントであり、提供されたイベントでstopImmediatePropagation()を呼び出すと、この要素に登録されている他のリスナーの実行が停止することです。 ただし、Angularを介して登録されたすべてのリスナーは、(パフォーマンス上の理由により)このイベントでstopImmediatePropagationを呼び出すだけのdomリスナーによってプロキシされるため、効果はありません。
ネイティブの追加および削除EventListenersを使用できます。これは、angular用語で考えた場合、決して良い解決策ではありません。また、disabled
属性をbutton
に入れた場合、これは機能しません。添付のeventListenersをオーバーライドします。代わりにdisabled
クラスを使用する必要があります(または、button
でspan
をラップし、そのテンプレート参照#btn
を使用します)。
import { Component, OnInit, OnChanges, HostListener, Input, Output, EventEmitter, SimpleChanges, ElementRef, ViewChild } from '@angular/core';
@Component({
selector: 'app-my-button',
template: `<button [class.disabled]="isDisabled" #btn><span>hey</span></button>`,
styles: [`button.disabled { opacity:0.5 }`]
})
export class MyButtonComponent implements OnInit, OnChanges {
disableClick = e => e.stopPropagation();
@Input() isDisabled: boolean;
@ViewChild('btn') btn: ElementRef;
constructor() { }
ngOnChanges(changes: SimpleChanges) {
if(this.isDisabled) {
this.btn.nativeElement.addEventListener('click', this.disableClick);
} else {
this.btn.nativeElement.removeEventListener('click', this.disableClick);
}
}
ngOnInit() {
}
}