Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get reference to currently active HTMLElement

So I have an Angular 2 and Typescript project, and I want to clear all focus on the page on a specific click.

Right now I am just using document.activeElement to get the currently active element, and then calling .blur() on it. However this is not symantically correct, and of course TypeScript is throwing a fit about it (and rightfully so).

Is there any way I can accomplish the same thing, but ensure that I am referencing an HTMLElement instead of Element so I can keep things typed correctly?

Basically I am calling a function to close all sub-menus when A) The sub-nav is clicked and the menu item clicked is already open, and B) When the document is clicked anywhere that's not a menu item.

Here is the function that is called:

closeMenus = function(){
    for (var i=0, j=this.openElements.length; i<j; i++){
        this.openElements[i] = false;
    };

    document.activeElement.blur();
};

This gives the error:

Property 'blur' does not exist on type 'Element'

Which is absolutely correct, it exists on HTMLElement. However if I add this line:

console.log(document.activeElement instanceof HTMLElement);

This returns true. So I am extremely confused about exactly what TypeScript wants here?

like image 228
StephenRios Avatar asked Nov 01 '16 19:11

StephenRios


2 Answers

The activeElement of the document can be any Element, not just an HTMLElement. At compile time the compiler does not know what type the element will be. Hence, if you surround the call with an instanceof check, the compiler knows the activeElement has to be an HTMLElement for the code to execute and allows the reference.

if (document.activeElement instanceof HTMLElement) {
  document.activeElement.blur();
}

This approach does not require you to jump through hoops of getting different Angular bindings to execute the method that is already available to you. Less code and less dependencies!

like image 152
Brian Bauman Avatar answered Sep 21 '22 01:09

Brian Bauman


Inject a Renderer into your component/directive.

Get a hold of any elementRef (for example your button or link).

constructor(private elRef: ElementRef, private renderer: Renderer){
}

then in your handler function:

this.renderer.invokeElementMethod(
     this.elRef.nativeElement.ownerDocument.activeElement, 'blur');
like image 25
Meir Avatar answered Sep 21 '22 01:09

Meir