简体   繁体   中英

How to put the focus of an input in a form-field with ngIf

I am faced with a problem, I want in my code, to put the focus on a conditioned input based on data from an observable. In my example I just set a boolean to true in the ngOnInit() .

export class InputOverviewExample implements OnInit {
  bool: boolean;

  @ViewChild("input1", { static: true }) input1: MatInput;
  @ViewChild("input2", { static: true }) input2: MatInput;

  ngOnInit() {
    this.bool = true;
    this.input1.nativeElement.focus();
    this.input2.nativeElement.focus();
  }
}

And I noticed that the focus is not working when a mat-form-field is conditioned.

<form class="example-form">
  <h3>Without *ngIf :</h3>
  <mat-form-field appearance="outline" class="example-full-width">
    <input matInput #input1 placeholder="Auto focus" value="Test_input1" />
  </mat-form-field>

  <h3>With *ngIf :</h3>
  <mat-form-field appearance="outline" class="example-full-width" *ngIf="bool">
    <input matInput #input2 placeholder="Auto focus" value="Test_input2" />
  </mat-form-field>
</form>

StackBlitz link

Someone would have a solution to this problem

Thank you

you need understand ViewChild {static:true} and {static:false} and {read}

So, first define your ViewChild as

@ViewChild("input1", { static: false,read:ElementRef }) input1: ElementRef;
@ViewChild("input2", { static: false,read:ElementRef }) input2: ElementRef;

The static:false makes that Angular check if is under a *ngIf

The read:ElementRef makes that your "input1" and "input2" are saw as ElementRef, not as MatInput

The second thing that you need is how Angular works. Angular execute all the actions and refresh the application, so if you write

this.bool = true;
this.input2.nativeElement.focus(); //<--this.input2 is undefined

this.input2 is undefined because Angular has not repaint the application, so you need enclosed by setTimeout -you can think about setTimeout like you say to Angular "hey, don't forget that after refresh the appication, you need make this another instuctions"- or use ChangeDetectorRef .

So

  ngOnInit() {
    this.bool = true;
    setTimeout(()=>{
      this.input1.nativeElement.focus();
      this.input2.nativeElement.focus();
    })
  }
ngOnInit() {
    this.bool = true;
    if(...){
        this.input1.nativeElement.focus();
    }
    else{
        this.input2.nativeElement.focus();
    }
    
}

Use QueryList to query element

import { Component, OnInit, ViewChild,   
QueryList,
  ViewChildren, ElementRef, AfterViewInit, ChangeDetectorRef } from "@angular/core";
import { MatInput } from "@angular/material";
import {startWith} from 'rxjs/operators';

/**
 * @title Basic Inputs
 */
@Component({
  selector: "input-overview-example",
  styleUrls: ["input-overview-example.css"],
  templateUrl: "input-overview-example.html"
})
export class InputOverviewExample implements OnInit, AfterViewInit {
  bool: boolean;
  @ViewChild("input1", { static: true }) input1: MatInput;
  // @ViewChild("input2", { static: true }) input2: MatInput;
  @ViewChildren('input2') input2: QueryList<ElementRef>;

constructor(private cd: ChangeDetectorRef) {

}
  ngOnInit() {
    this.bool = true;
    this.input1.nativeElement.focus();
  }

  ngAfterViewInit(): void {
     this.input2.changes
     .pipe(
        startWith(true),
      )
      .subscribe(() => {
        this.input2.forEach((elementRef: ElementRef) => {
          if(elementRef) {
             elementRef.nativeElement.focus();
             this.cd.detectChanges();
          }
        });
      });
  }
}

DEMO

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM