14

-- Not duplicate! Since the other questions are outdated. Not duplicate with the asked question!!!!

this.elm.nativeElement.ownerDocument.activeElement

also

document.activeElement

gives me strangely enough the whole body.How can i just get the current focused element?

  • elm = type of ElementRef which is bound in my component's constructor.

  • from another question here: this.renderer.invokeElementMethod is also not callable since Renderer is now deprecated and Renderer2 does obviously not have that method anymore.

EDIT: This question answers this problem partially:

document.activeelement returns body

Between leaving the old element and entering the new element the active element is indeed the document/body itself.

akcasoy
  • 6,497
  • 13
  • 56
  • 100
  • Try adding "autofocus" attribute. Try with ngIf also – Debojyoti Sep 27 '18 at 07:06
  • 1
    Possible duplicate of [How do I find out which DOM element has the focus?](https://stackoverflow.com/questions/497094/how-do-i-find-out-which-dom-element-has-the-focus) – Antoniossss Sep 27 '18 at 07:10
  • The fact that you dont have focus on ANY meaningful element does not make this question unique, but a duplicate and special case . – Antoniossss Sep 27 '18 at 07:11
  • document.activeElement gives me also the whole body! – akcasoy Sep 27 '18 at 08:16
  • to answer this question some more context is needed. – sancelot Oct 01 '18 at 13:34
  • i am looking for something similar and am quite shocked, that there aren't any helpful answers out there yet. i need to hide a child element of a parent, if another element with the same parent is not focused – Alan Aug 28 '19 at 10:41

2 Answers2

12

I had to cover "document.activeElement" or "this.elm.nativeElement.ownerDocument.activeElement" inside a timeout, so that the active element is checked by the next angular lifecycle. Otherwise, when "X.activeElement" is executed just after the focus change, you get the whole body since while entering the new element the active element is indeed the document/body itself.

setTimeout(function() {
  X = document.activeElement;
});

Edit für ES6 (where "this" also can be used):

setTimeout(() => {
  X = document.activeElement;
});
akcasoy
  • 6,497
  • 13
  • 56
  • 100
  • Remember that the scope of 'this.*' changes in a setTimeout, it can pay to assign it to another variable to use within setTimeout. That caused me some minor fuss in following this solution. – Dessus Sep 17 '19 at 01:48
  • 2
    Since ES6, the best practice is to use [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). Then `this` will be the scope you expect (the scope in which the setTimeout is defined). – uɥƃnɐʌuop Aug 11 '20 at 11:35
3

I had a problem similar to this before. My issue was that I was using "tabindex" on non-form elements, but I needed to plug in an "onfocus" event to invoke a component action.

Two options worked for me:

1 Directive

    @Directive({
      selector: '[componentFocus]'
    })
    export class ComponentFocus {
      @HostListener('focus')
      componentFocus() {
        console.log(`component has focus, element:`, this.el);
      }
    
      constructor(private el: ElementRef) {
      }
    }

Then invoke on something like a fieldset:

    <fieldset tabindex="1" componentFocus>...</fieldset>

2 Simply use "on-focus" canonical form

    <fieldset tabindex="1" on-focus="onFocus($event.target)">...</fieldset>
Community
  • 1
  • 1