简体   繁体   English

Angular 5-当用户在目标元素之外单击时如何触发事件

[英]Angular 5 - How to trigger event when user clicks outside targeted elements

I need to be able to register when a user clicks outside targeted elements. 我需要能够在用户单击外部目标元素时进行注册。 To do this I have created a custom attribute directive shown below. 为此,我创建了一个自定义属性指令,如下所示。


ClickOutsideTargets Directive ClickOutsideTargets指令

import { Directive, ElementRef, Input, Output, EventEmitter, HostListener } from '@angular/core';

@Directive({
  selector: '[clickOutsideTargets]',
})
export class ClickOutsideTargetsDirective {

    @Input()
    public targets : HTMLElement[] = [];


    @Output() 
    clickOutsideTargets = new EventEmitter();

    constructor(){

    }


    @HostListener('document:click', ['$event.target'])
    public onClick(targetElement){

     if(!targetElement){
        return;
    }

    for(var i = 0, len = this.targets.length; i < len; i++){
        if(this.targets[i].contains(targetElement)){
            return;
        }
    }

    this.clickOutsideTargets.emit(null);

  }

}

The 'targets' array specifies the elements where the user can click without triggering an event. “目标”数组指定用户可以在不触发事件的情况下单击的元素。 Whenever the user clicks outside these elements an event is emitted. 每当用户在这些元素之外单击时,都会发出一个事件。


I want to be able to pass an array of targets to the directive as an input, using the following syntax which is clean and convenient. 我希望能够使用干净且方便的以下语法将目标数组传递给指令作为输入。 Each target is given as a template variable (#variable). 每个目标均作为模板变量(#variable)给出。

<button #buttonRef class="btn btn-primary" (click) = "activate()" (clickOutsideTargets) = "deactivate()" [targets] = "[buttonRef, containerRef]"> </button>



Issues with this approach 这种方法的问题

However, this doesn't work when- 但是,这在以下情况下不起作用:

  • One of the target elements exists in the template of a child component. 目标元素之一存在于子组件的模板中。 Unless there is a way to access a child's template variables from the parent component's template. 除非有一种方法可以从父组件的模板访问子模板的变量。

  • One of the target elements is created dynamically, for example through an NgFor. 目标元素之一是动态创建的,例如通过NgFor。


Is there a way to solve these issues? 有办法解决这些问题吗? Or ideally, is there a better solution/strategy that I'm not considering. 或者理想情况下,有没有我没有考虑的更好的解决方案/策略。


(One really messsy solution to get the functionality is by creating a new template variable to represent the directive (using exportAs within the directive's decorator), accessing the directive within the parent component using ViewChild, accessing the target elements using ViewChild/ViewChildren and manually setting the directive's target array to the necessary elements.) This breaks the principle of lean components. (获得该功能的一个非常混乱的解决方案是创建一个新的模板变量来表示指令(使用指令的装饰器中的exportAs),使用ViewChild访问父组件中的指令,使用ViewChild / ViewChildren访问目标元素并手动设置指令的目标数组指向必要的元素。)这打破了精益组件的原理。

You might want to try this 您可能想尝试一下

In your Component 在您的组件中

@ViewChild('myTarget') myTarget;

@HostListener('document:click', ['$event.target'])
    onClick(targetElement) {
        const clickedInside = this.myTarget.nativeElement.contains(targetElement);
        if (!clickedInside) {
            //the click was made outside of this element
        }
    }

In your html 在你的HTML

<div #myTarget>
</div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM