Lempkin
Lempkin

Reputation: 1588

ViewChild and focus()

I have a component which contains a textarea which is hidden by default :

<div class="action ui-g-2" (click)="toggleEditable()">edit</div>
<textarea [hidden]="!whyModel.inEdition" #myname id="textBox_{{whyModel.id}}" pInputTextarea focus="true" [(ngModel)]="whyModel.description"></textarea>

When I click on the "edit" div I want to show the textarea and put focus on it :

@ViewChild('myname') input: ElementRef;
...
private toggleEditable(): void {
  this.whyModel.toggleEditable();
  this.input.nativeElement.focus();
}

The "show" part is working but not the focus part. What do I miss?

Upvotes: 12

Views: 27978

Answers (4)

Patrick
Patrick

Reputation: 2195

If you are trying to focus on a custom Angular component (like a custom modal/dialog implementation nested inside another component), you may need to add a tabIndex to it:

You can either do this directly in the template. E.g.:

<div class="my-modal" tabIndex="0">...</div>

Or via a @ViewChild decorator in your component Typescript code. E.g.:

...
@ViewChild("myModal") myModal: ElementRef;
...
ngAfterViewInit()() {
  this.myModal.nativeElement.tabIndex = "0";
  this.myModal.nativeElement.focus();
}

Hope this helps someone!

Upvotes: 0

Akshay Yadav
Akshay Yadav

Reputation: 1

You can use @ViewChild and focus() to focus on a particular element. It can be used like this:

In HTML file (abc.component.html)

<form #data="ngForm">
<input class="text-field" type="text" name="name" >
<input class="text-field" type="text" name="surname">
<input class="text-field" type="text" name="company">
</form>


<button type="submit" value="Submit" (click)="submitData(data.value)">Submit</button>


<input class="text-field" type="text" name="City" #setFocusField>
<input class="text-field" type="text" name="State">

In TypeScript file (abc.component.ts)

@ViewChild('setFocusField') setFocusField: any;

submitData(data:any){
  this.setFocusField.focus();
}

When you click on the submit button, the focus will be set to the field "City".

Another way to achieve this:

In above code, instead of any on ViewChild field, we can use ElementRef.

In that case typescript file changes will be as follow:

(abc.component.ts)

@ViewChild('setFocusField') setFocusField: ElementRef;

submitData(data:any){
  this.setFocusField.nativeElement.focus();
}

Upvotes: 0

Vega
Vega

Reputation: 28708

You can also 'force' the focus with AfterViewCheck. I simplified your code for the demo purposes:

Typescript:

  editable;

  @ViewChild('myname') input: ElementRef;
  private toggleEditable(): void {
      this.editable = !this.editable;
   }

   ngAfterViewChecked(){
     if(this.editable){
          this.input.nativeElement.focus();
     }
   }

HTML

<div class="action ui-g-2" (click)="toggleEditable()">edit</div>
<br>
<textarea [hidden]="!editable" #myname id="textBox_{{id}}" pInputTextarea
   focus="true" [(ngModel)]="description"></textarea>

Stackblitz example

Upvotes: 3

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657308

Bindings are only updated when change detection runs, which is usually after an event handler completed. This is to late for your use case, because the event handler itself depends already on the effect of change detection.

You can enforce change detection immediately (synchronically) by calling detectChanges()

constructor(private cdRef:ChangeDetectorRef) {}

@ViewChild('myname') input: ElementRef;
...
private toggleEditable(): void {
  this.whyModel.toggleEditable();
  this.cdRef.detectChanges();
  this.input.nativeElement.focus();
}

Upvotes: 17

Related Questions