mr__brainwash
mr__brainwash

Reputation: 1382

How to remove disabled attribute and focus input Angular 5?

I am a bit confused trying to focus input that was disabled. I have input that is disabled at start. And after clicking a button i want remove disabled attr and focus this input.

I removed attribute from the input before focus this.renderer.removeAttribute(this.elRef.nativeElement, 'disabled'); and then tried to focus input this.input.nativeElement.focus(); .

Where this.input is @ViewChild('input') input: ElementRef; Disabled attribute disappears, but input is not focused. Here is jsfidle I also tried bind to [attr.disabled] , but it didn't help.

What is the best solution for dynamic focus on the element and manipulating DOM's attributes in Angular? Btw i am using the latest Angular.

Upvotes: 0

Views: 6250

Answers (2)

yurzui
yurzui

Reputation: 214067

elRef is your host element that doesn't have disabled attribute

this.renderer.removeAttribute(this.elRef.nativeElement, 'disabled');
                                   ^^^^^
                             seems input should be here

Plunker Example

Update

Why input is not focused in this case? I toggled isDisabled - so disabled attr should be setted to null, am i wrong? An then we should be able to focus on input

That's because how angular change detection mechanism works.

It will be setted to null but only after next VM turn when there are no microtasks. Angular uses zone.js to run change detection.

this.isDisabled = !this.isDisabled; // 1) you only change property
this.input.nativeElement.focus();  // 2) you executed focus(input is still disabled)
....
....
AppRef
  zone.onMicrotaskEmpty.subcribe(() => run change detection) // 3) your template is updated

You have several options to overcome this problem:

1) Using Renderer2 API as shown at the beginning of the answer

2) Subscribe to onMicrotaskEmpty event Example

import { take } from 'rxjs/operators/take';

constructor(private zone: NgZone) {}

focus() {
  this.isDisabled = !this.isDisabled;

  this.zone.onMicrotaskEmpty.pipe(
    take(1)
  ).subscribe(() => {
    this.input.nativeElement.focus();
  });
}

In this case angular app won't call addition change detection cycle.

3) Using setTimeout as was suggested in another answer.

Your angular application will additionally check full component tree.

4) Using ChangeDetectorRef.detectChanges() method was suggested in comments of another answer.

this.isDisabled = !this.isDisabled; 
this.cdRef.detectChanges();
this.input.nativeElement.focus();

Additional check only this component and its children

Upvotes: 2

Nickolaus
Nickolaus

Reputation: 4835

There is no need for the renderer at all, all you need is to wait one tick in so the view will be updated, therefore the nativeElement is no more disabled and can be focused:

focus() {
   this.isDisabled = !this.isDisabled;
   setTimeout(() => {
      this.input.nativeElement.focus();
   });
}

Upvotes: 4

Related Questions