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
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).
<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.
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.