Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 roll-my-own dropdown hide if clicking away?

Tags:

angular

I have a div that I want to show/hide on focus/blur of an input. Here's a simplified version of what I'm trying:

<input (focus)="ShowDropDown=true;" (blur)="ShowDropDown=false;" />
<div *ngIf="ShowDropDown">
  <ul>
    <li (click)="...">...</li>
    <li (click)="...">...</li>
    <li (click)="...">...</li>
  </ul>
</div>

This div contains a list of elements to click on. My problem is that the input's blur is happening before the li's click.

I want to keep things simple. I don't want to set everything's focus or click event to set ShowDropDown=false but I need to keep the dropdown div open for interaction.

I could have ShowDropDown be a number where focusing adds 1 to it, mousing over the div adds another 1 to it, blurring the input subtracts 1, and mousing out of the div subtracts 1 but I imagine that could go out of sync really easily.

Is there a simpler way to do this? Can I force blur to run after click?

like image 518
Corey Ogburn Avatar asked Feb 04 '16 21:02

Corey Ogburn


2 Answers

I found the answer in this question: mousedown will happen before blur but click will happen after. I simply change to

<input (focus)="ShowDropDown=true;" (blur)="ShowDropDown=false;" />
<div *ngIf="ShowDropDown">
  <ul>
    <li (mousedown)="...">...</li>
    <li (mousedown)="...">...</li>
    <li (mousedown)="...">...</li>
  </ul>
</div>

This gives me the order of events I want without doing delays or "reference counting" where the mouse is or adding a click event to everything else in the DOM.

like image 132
Corey Ogburn Avatar answered Sep 28 '22 04:09

Corey Ogburn


Update

A better way to listen to global events is

@Comonent({...
  host: {'(window:click)': 'clickHandler()'}
})

Original

Just check if the click was inside or outside your dropdown:

import {DOM} from angular2/platform/common_dom;

constructor(private elementRef: ElementRef) {
  DOM.getGlobalEventTarget('window')
     .addEventListener('click', (event) => {
       // check if event.target is a child of elementRef.nativeElement
       // if not hide the dialog
     });
}

I cant currently make this work in TS though DOM is always undefined.
This works fine in Dart.
Plunker

I created an issue https://github.com/angular/angular/issues/6904

like image 32
Günter Zöchbauer Avatar answered Sep 28 '22 03:09

Günter Zöchbauer