Search code examples
angularfocus

Focus on input inside ngFor


When user clicks on button, addElement method will push object to array of elements and new input field will be created. Is it possible to focus on the newly created element? Inputs don't have distinctive IDs.

Template:

<div *ngFor="let foo of elements">
  <input class="input" value="{{ foo.value }}" />
</div>
<button (click)="addElement()"></button>

Method:

public addElement() {
  this.elements.push({ value: 'new' });
}

I'm using Angular 9 in this application.


Solution

  • You need to query all inputs via ViewChildren decorator, then every time addElement called the ngAfterViewChecked will be called too. So you may use this hook to focus the last already created input.

    <div *ngFor="let foo of elements">
      <input 
        #input 
        class="input" 
        [value]="foo.value"
      />
    </div>
    <button (click)="addElement()"></button>
    
    @ViewChildren('input') inputs: QueryList<ElementRef>;
    
    addElement() {
      this.elements.push({ value: 'new' });
    }
    
    ngAfterViewChecked() {
      this.inputs.last.nativeElement.focus();
    }
    

    Otherwise you can do check by yourself and don't rely on lifecycle hook because this logic in ngAfterViewChecked may affect smth in your app:

    @ViewChildren('input') inputs: QueryList<ElementRef>;
    
    constructor(private changeDetectorRef: ChangeDetectorRef) {
    }
    
    addElement() {
      this.elements.push({ value: 'new' });
      /* run change detection manually to create input element and have access to the last input */
      this.changeDetectorRef.detectChanges();
      this.inputs.last.nativeElement.focus();
    }
    

    https://angular.io/api/core/ViewChildren#description

    https://angular.io/guide/lifecycle-hooks#lifecycle-event-sequence