question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

(focusout) is triggered a full 150 milliseconds before (click) and that is anti-pattern

See original GitHub issue

I’m submitting a…


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  
[ ] Performance issue
[X] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:

Current behavior

say you have a focused div with a focusout directive and a click in order to counteract the focusout :

<div
  tabindex="1"
  *ngIf="importCsvOpen"
  [@dropDownAnimation]
  (click)="clickInside()"
  [ngClass]="dropzoneHovered ? 'dragged' : ''"
  class="dropzone-container"
  (dragover)="dropzoneHovered = true"
  (dragleave)="dropzoneHovered = false"
  (focusout)="focusOut()"
  myAutofocus>

focusout is inherently superior to @HostListener('document:click', ['$event']) clickedOutside(e){ because it means we no longer need to rely on beacons (classes, ids, jquery select, ect…) which are unreliable at best and have very little code robustness (someone else picks up the project, forgets to include the beacon class in his modifications then scratches his head at why his code doesn’t work)

focusout on the other hand is a method call, that is contained and in a controlled environment has a single point of origin and can be traced.

all that’s left is the ability to have the same cleanliness on the !focusout.

what if I click on the focused element?

not only does this trigger focusout but focusout is prioritary by an obscene order of magnitude.

I thought I could simply allow a bit of dirty code to fix the fact that Angular put (focusout) before (click) in runtime myself :

clickIn = false;
clickInside(){
    this.clickIn = true;
    setTimeout(()=> this.clickIn = false, 9);
}
focusOut(){
    if(!this.clickIn){
        this.importCsvOpen = false;
        this.dropzoneHovered = false;
    }
}

but that would turn out not to be enough because focusOut was being called before clickIn, so I had to make things worse :

clickIn = false;
clickInside(){
    this.clickIn = true;
    setTimeout(()=> this.clickIn = false, 190);
}

focusOut(){
    setTimeout(()=> {
      if(!this.clickIn){
        this.importCsvOpen = false;
        this.dropzoneHovered = false;
    }
  }, 150);
}

As you can see my attempt is to disallow the hiding of my dropzone if it was the dropzone itself that was clicked and I would know this as a certainty without having to use “beacons” if the origin of the (click) method is the div that I am talking about and of course that, contrary to the “beacon” method, is the only possibility if we’re using the (click) method on that div.

the problem then comes from trying to get the click method to be called before the focusout method and I couldn’t come up with another way to do this other than timeouts.

Were I loose all hope is that the delay required to actually succeed in this is utterly obscene.

I understand that there’s a lot going on with that div but how is Angular triggering (click) 150 milliseconds after the (focusout). there must be some sort of performance issue here too.

Thinking long and hard about it I have come to the conclusion that there could not be a use-case for requirering (focusout) being called before (click) that wouldn’t be immediately remedied by using (click) like I did, except with the inverse of the boolean logic demonstrated above.

Expected behavior

that (click) always trigger before (focusout).

as an added bonus focusout shouldn’t be triggered by clicking on the focused div that itself is the issuer of the focusout call. Which does not make sense to me. (but if it stays that way I can work around that, given (click) is brought up in the priority chain)

Minimal reproduction of the problem with instructions

https://stackblitz.com/edit/angular-gitter-u7erfg?file=app%2Fapp.component.ts

What is the motivation / use case for changing the behavior?

the other way around would make much more sense and be much more useful to people

Environment

Angular version: 6.0.4

Browser:

  • [x ] Chrome (desktop) version XX
  • [x ] Chrome (Android) version XX
  • [x ] Chrome (iOS) version XX
  • [x ] Firefox version XX
  • [x ] Safari (desktop) version XX
  • [x ] Safari (iOS) version XX
  • [x ] IE version XX
  • [x ] Edge version XX

For Tooling issues:

  • Node version: v8.9.4
  • Platform: Windows

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

6reactions
tatsujbcommented, Sep 11, 2018

what I’m saying is they should. there’s every motive to do so. they could gain additional functionality and code cleanliness as well as runtime reliability as well as potentially utilize those to unlock new capabilities that the other frameworks won’t have. And from where I’m standing this overall could mean optimization and performance also.

2reactions
robwormaldcommented, Sep 11, 2018

As @sarunint says, Angular is doing nothing special here, and we are not doing anything like Angularfocusout(args){ js.focusout(args)}.

focusout on the other hand is a method call, that is contained and in a controlled environment has a single point of origin and can be traced.

focusout is a DOM Event, (not a method) and so internally, <input (focusout)="doStuff()"> literally gets compiled to input.addEventListener('focusout', e => component.doStuff()). The browser triggers it, Angular does not!

In general, we smooth over the rough edges where possible, without changing the semantics of how the DOM works. This would appear to dramatically change the native behavior (however irritating it is), and we’re not likely to do that.

Read more comments on GitHub >

github_iconTop Results From Across the Web

jQuery focusout event on form element is triggered even when ...
This happens because you are in-fact not focusing on the form, but rather on one of its child elements (input or button in...
Read more >
Element: focusout event - Web APIs | MDN
The focusout event fires when an element has lost focus, after the blur event. The two events differ in that focusout bubbles, while...
Read more >
Diff - ca9862fcfe..20e23fa31a - chromium/src - Git at Google
+ private long mLoadDecisionMs; + // Records whether a preload was triggered. + boolean mTriggerPreload; + public static void failNextTabMatchForTesting() ...
Read more >
.focusout() | jQuery API Documentation
trigger ( "focusout" ) when no arguments are passed. The focusout event is sent to an element when it, or any element inside...
Read more >
Untitled
Beer left too long before bottling, Milestonesys smart client, Women's studies umd, ... Death ship 1980 full movie online, Diagnosis of ms later...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found