How to execute click function before the blur function
Replace your click event with (mousedown). Mousedown event is called before blur. This code should works properly:
<input (focus)="showDropdown()" (blur)="myBlurFunc()">
<ul>
<li *ngFor="let item of dropdown" (mousedown)="myClickFunc()">{{item.label}}</li>
</ul>
It looks like click event has lower priority than blur, so it is predictible behaviour that blur event fires first.
Here's another way to solve this, and it requires no JS:
.menu {
display: none;
}
.toggle:focus + .menu,
.toggle + .menu:active {
display: block;
}
<button class="toggle">menu</button>
<ul class="menu">
<li onClick="console.log('tacos')">tacos</li>
<li onClick="console.log('burgers')">burgers</li>
</ul>
The secret is to target not only the .toggle:focus
state, but also the .menu:active
state.
Make the options in your dropdown elements that can receive focus - use <a>
or <button>
or set tabindex="-1"
. Then, in your onBlur
handler, check event.relatedTarget
. In an onBlur
handler, relatedTarget
is the element receiving focus (if there is one). If it is one of the options in your dropdown, then you know not to hide the options at this point.
This is preferable over switching from onClick
to onMouseDown
, because an actual click doesn't always immediately follow a mouseDown. If you mousedown, move the cursor off, then mouseup, you'll trigger a mousedown without triggering a click at all.
const elToggle = document.querySelector('.toggle');
const elMenu = document.querySelector('.menu');
elToggle.onfocus = (event) => {
elMenu.classList.add('open');
};
elToggle.onblur = (event) => {
const didClickMenu = elMenu.contains(event.relatedTarget);
if (!didClickMenu) {
elMenu.classList.remove('open');
}
};
.menu {
display: none;
}
.menu.open {
display: block;
}
<button class="toggle">menu</button>
<ul class="menu">
<li tabIndex="-1" onClick="console.log('tacos')">tacos</li>
<li tabIndex="-1" onClick="console.log('burgers')">burgers</li>
</ul>