Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 focus doesn't work if I don't use timeout

Tags:

angular

As you can see i'm using setTimeout if i'm planning to focus my input. If i remove setTimeout focus doesn't work.

  <div [hidden]="searchInputHidden">
        <input (blur)="hideInput()" #term (keyup)="search(term.value)" type="text" class="inp_top" name="product_name" id="product_name" />
  </div>  


private showSearchInput(term) {
    this.searchInputHidden = false;
    setTimeout(function(){
      term.focus();
    }, 100);
  }
like image 746
Arturs Soms Avatar asked Mar 02 '16 16:03

Arturs Soms


1 Answers

The timeout is required because you can't focus() an element that is still hidden. Until Angular change detection has a chance to run (which will be after method showSearchInput() finishes executing), the hidden property in the DOM will not be updated, even though you set searchInputHidden to false in your method.

A setTimeout() with a value of 0 (or no value, which defaults to 0) should work. You just need to set the focus after Angular gets a chance to update the hidden property value.


Note that after the setTimeout() callback function finishes executing, change detection will run again (because Angular monkey-patches all setTimeout() calls that are made in the Angular zone). Since the only thing we are changing in our asynchronous callback function is the focus, we can be more efficient and run our callback function outside the Angular zone, to avoid the additional change detection cycle:

private showSearchInput(term) {
  this.searchInputHidden = false;
  this._ngZone.runOutsideAngular(() => { 
    setTimeout(() => term.focus());
  });
}

Note that you'll have to inject NgZone into your constructor for the above code to work:

export class YourComponent {
   constructor(private _ngZone: NgZone) {}
like image 54
Mark Rajcok Avatar answered Sep 19 '22 15:09

Mark Rajcok