Yanıtlar:
import { Component, ElementRef, HostListener, Input } from '@angular/core';
@Component({
selector: 'selector',
template: `
<div>
{{text}}
</div>
`
})
export class AnotherComponent {
public text: String;
@HostListener('document:click', ['$event'])
clickout(event) {
if(this.eRef.nativeElement.contains(event.target)) {
this.text = "clicked inside";
} else {
this.text = "clicked outside";
}
}
constructor(private eRef: ElementRef) {
this.text = 'no clicks yet';
}
}
AMagyar'ın cevabına bir alternatif. Bu sürüm, bir ngIf ile DOM'dan kaldırılan öğeye tıkladığınızda çalışır.
http://plnkr.co/edit/4mrn4GjM95uvSbQtxrAS?p=preview
private wasInside = false;
@HostListener('click')
clickInside() {
this.text = "clicked inside";
this.wasInside = true;
}
@HostListener('document:click')
clickout() {
if (!this.wasInside) {
this.text = "clicked outside";
}
this.wasInside = false;
}
@ Hostlistener aracılığıyla belge tıklamaya bağlanmak maliyetlidir. Aşırı kullanırsanız (örneğin, özel bir açılır pencere bileşeni oluştururken ve bir formda oluşturulmuş birden çok örneğiniz varsa) performans üzerinde gözle görülür bir etkisi olabilir ve olacaktır.
Ana uygulama bileşeninizin içinde yalnızca bir kez belge tıklama etkinliğine bir @Hostlistener () eklemenizi öneririm. Olay, tıklanan hedef öğenin değerini global bir yardımcı program hizmetinde depolanan herkese açık bir konu içinde itmelidir.
@Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>'
})
export class AppComponent {
constructor(private utilitiesService: UtilitiesService) {}
@HostListener('document:click', ['$event'])
documentClick(event: any): void {
this.utilitiesService.documentClickedTarget.next(event.target)
}
}
@Injectable({ providedIn: 'root' })
export class UtilitiesService {
documentClickedTarget: Subject<HTMLElement> = new Subject<HTMLElement>()
}
Tıklanan hedef öğeyle ilgilenen herkes, yardımcı programlar hizmetimizin genel konusuna abone olmalı ve bileşen yok edildiğinde abonelikten çıkmalıdır.
export class AnotherComponent implements OnInit {
@ViewChild('somePopup', { read: ElementRef, static: false }) somePopup: ElementRef
constructor(private utilitiesService: UtilitiesService) { }
ngOnInit() {
this.utilitiesService.documentClickedTarget
.subscribe(target => this.documentClickListener(target))
}
documentClickListener(target: any): void {
if (this.somePopup.nativeElement.contains(target))
// Clicked inside
else
// Clicked outside
}
Yukarıda belirtilen cevaplar doğrudur, ancak ilgili bileşenden odak noktasını kaybettikten sonra ağır bir işlem yapıyorsanız ne olur? Bunun için, odaklanma olayının yalnızca ilgili bileşenden odak kaybedildiğinde gerçekleşeceği iki bayraklı bir çözümle geldim.
isFocusInsideComponent = false;
isComponentClicked = false;
@HostListener('click')
clickInside() {
this.isFocusInsideComponent = true;
this.isComponentClicked = true;
}
@HostListener('document:click')
clickout() {
if (!this.isFocusInsideComponent && this.isComponentClicked) {
// do the heavy process
this.isComponentClicked = false;
}
this.isFocusInsideComponent = false;
}
Umarım bu sana yardımcı olur. Bir şey kaçırdıysanız beni düzeltin.
Https://www.npmjs.com/package/ng-click-outside paketindekilickOutside () yöntemini kullanabilirsiniz.
ginalx'in cevabı varsayılan bir imo olarak ayarlanmalıdır: bu yöntem birçok optimizasyona izin verir.
Sorun
Bir öğe listemiz olduğunu ve her öğede geçiş yapması gereken bir menü eklemek istediğimizi varsayalım. click
Kendi başına bir olayı dinleyen bir düğmeye bir geçiş ekliyoruz (click)="toggle()"
, ancak aynı zamanda kullanıcı dışını tıkladığında menüyü değiştirmek istiyoruz. Öğe listesi büyürse ve bir@HostListener('document:click')
her menüye bir eklersek, öğeye yüklenen her menü, menü kapatıldığında bile tüm belgenin tıklanmasını dinlemeye başlayacaktır. Bariz performans sorunlarının yanı sıra, bu gereksizdir.
Örneğin, pop-up bir tıklama ile değiştirildiğinde abone olabilir ve ancak o zaman "dış tıklamaları" dinlemeye başlayabilirsiniz.
isActive: boolean = false;
// to prevent memory leaks and improve efficiency, the menu
// gets loaded only when the toggle gets clicked
private _toggleMenuSubject$: BehaviorSubject<boolean>;
private _toggleMenu$: Observable<boolean>;
private _toggleMenuSub: Subscription;
private _clickSub: Subscription = null;
constructor(
...
private _utilitiesService: UtilitiesService,
private _elementRef: ElementRef,
){
...
this._toggleMenuSubject$ = new BehaviorSubject(false);
this._toggleMenu$ = this._toggleMenuSubject$.asObservable();
}
ngOnInit() {
this._toggleMenuSub = this._toggleMenu$.pipe(
tap(isActive => {
logger.debug('Label Menu is active', isActive)
this.isActive = isActive;
// subscribe to the click event only if the menu is Active
// otherwise unsubscribe and save memory
if(isActive === true){
this._clickSub = this._utilitiesService.documentClickedTarget
.subscribe(target => this._documentClickListener(target));
}else if(isActive === false && this._clickSub !== null){
this._clickSub.unsubscribe();
}
}),
// other observable logic
...
).subscribe();
}
toggle() {
this._toggleMenuSubject$.next(!this.isActive);
}
private _documentClickListener(targetElement: HTMLElement): void {
const clickedInside = this._elementRef.nativeElement.contains(targetElement);
if (!clickedInside) {
this._toggleMenuSubject$.next(false);
}
}
ngOnDestroy(){
this._toggleMenuSub.unsubscribe();
}
Ve içinde *.component.html
:
<button (click)="toggle()">Toggle the menu</button>
tap
operatöre yerleştirmemenizi öneririm . Bunun yerine kullanın skipWhile(() => !this.isActive), switchMap(() => this._utilitiesService.documentClickedTarget), filter((target) => !this._elementRef.nativeElement.contains(target)), tap(() => this._toggleMenuSubject$.next(false))
. Bu şekilde çok daha fazla RxJ kullanır ve bazı abonelikleri atlarsınız.
@J geliştiriliyor. Frankenstein cevap
@HostListener('click')
clickInside($event) {
this.text = "clicked inside";
$event.stopPropagation();
}
@HostListener('document:click')
clickout() {
this.text = "clicked outside";
}
u (odaklanma) veya (bulanıklaştırma) gibi olay işlevini çağırabilir ve ardından kodunuzu koyabilirsiniz
<div tabindex=0 (blur)="outsideClick()">raw data </div>
outsideClick() {
alert('put your condition here');
}