3

I am trying to create a directive for a drop-down, as long as I am working with single one it works like a charm. I can spot click outside dropdown using following code:

@HostListener('document:click', ['$event'])
  onDocumentClick(event: any): void {
    console.log("document click");
    // close
}
@HostListener('click')
  onClick(): void {
    console.log('click on ');  
    // toggle  
  }

The problem occurs when there are 2 dropdowns created. I would like close first drop-down when second is opened, however when I click on the second dropdown, only "click" event is getting triggered and "document.click" is not getting executed. I would expect that both events should occur unless I explicitly use preventDefault on click but apparently this happens automatically.

What should be correct approach in Angular 5 to close first drop-down when second is opened?

Dawid Adach
  • 749
  • 5
  • 27
  • I have tried using a directive to achieve this and was not successful. I had to add a private property to the Component and flag every time I open or close the dropdown to consider closing it when another dropdown is clicked. I followed the example code from [@J. Frankenstein](http://plnkr.co/edit/4mrn4GjM95uvSbQtxrAS?p=preview) – Erik Apr 09 '18 at 23:05

2 Answers2

0

Maybe you can try something like this:

 @HostListener('document:click', ['$event'])
  onClick(event) {
    if(this.eRef.nativeElement.contains(event.target)) {
      // toggle logic
    } else {
      // close logic
    }
}

So instead of having two events conflicting with each other you would have one event with two pieces of logic to handle exactly what you need depending if you clicked inside or outside the element itself. Makes sense?

This was taken from here

Hugo Noro
  • 3,145
  • 2
  • 13
  • 19
  • Thanks but "inside click" doesn't get triggered" -> if( this._element.nativeElement.contains(event.target)) { console.log('click on '); } doesn't work – Dawid Adach Dec 07 '17 at 10:56
  • Are you having errors or simply doesn’t get inside the if? – Hugo Noro Dec 07 '17 at 10:59
  • My bad, when I click on the drop-down, this doesn't get triggered at all. I put console log just before it and it's not getting triggered when I click on the dropdown itself. – Dawid Adach Dec 07 '17 at 14:27
-1

How about creating a directive that you can use everywhere ?

@Directive( {
    selector : '[clicked-outside]' ,
    host     : {
        '(document:click)' : 'onClick($event)',
        '(document:touch)' : 'onClick($event)',
        '(document:touchstart)' : 'onClick($event)'
    } 
} )
export class ClickedOutsideDirective {
    @Input( 'clicked-outside' ) callback : Function;

    constructor ( private _el : ElementRef ) {
    }

    private onClick ( event : any ) {
        if ( this.clickedOutside( event ) ) {
            if ( this.callback ) {
                this.callback();
            }
        }
    }

    private clickedOutside ( event : any ) {
        let clickedTarget = event.target;
        let host          = this._el.nativeElement;
        do {
            if ( clickedTarget === host ) {
                return false;
            }
            clickedTarget = clickedTarget.parentNode;
        } while ( clickedTarget );
        return true;
    }
}

and you can use it like this :

@Component({
   selector:'your-dropdown',
   template:`
       <div class="your-dropdown-top-most-wrapper" [clicked-outside]="onClickOutSide"></div>

   `
})
export class YouDropdownComponent{


   public onClickOutSide = ()=>{


        this.closeMyDropdown()// this is your function that closes the dropdown
   }
}
Milad
  • 27,506
  • 11
  • 76
  • 85