7

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?

Corey Ogburn
  • 24,072
  • 31
  • 113
  • 188

3 Answers3

8

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.

Community
  • 1
  • 1
Corey Ogburn
  • 24,072
  • 31
  • 113
  • 188
1

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

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
0

I can think of a simple hack like this

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

Not the most elegant solution, but should work

Gaurav Mukherjee
  • 6,205
  • 2
  • 23
  • 33
  • My click events in the li elements aren't running at all or I wouldn't need a work around. The blur happens first, sets ShowDropDown to false, the div is hidden, the click registers on the element behind the div. – Corey Ogburn Feb 05 '16 at 15:51