Search code examples
angularngrx

How to focus the nth-child in *ngFor with a mutating array


I have a list of items that are displayed it in my template with an *ngFor directive. An item in the array will be replaced, so it will be rerendered. I am trying to select a specific element in the *ngFor after this rerendering.

My first try

The code below works until an element is replaced from the array and the reference I used disappears.

my.component.html

<div *ngFor='let item of array'>
  <input #input type='text' [value]='item.name' \>
  <button (click)='select_function( input )'></button>
</div>

my.component.ts

@Component({
  // ...
})
export class MyComponent {
  public array: [] = [{name: 'Peter'}, {name: 'John'}]
  public select_function( element ) {
    element.focus();
  }
}

An incomplete solution

So I figured I should use the index somehow.

my.component.html

<div *ngFor='let item of array; let index = index;'>
  <input #input type='text' [value]='item.name' \>
  <button (click)='select_function(index)'>Modify</button>
</div>

my.component.ts

@Component({
  // ...
})
export class MyComponent {
  public array: [] = [{name: 'Peter'}, {name: 'John'}]
  public select_function( index) {
    // the array is mutated ( with ngrx in the actual situation )
    this.array.splice( index, 1, {name: 'Mary'} );
    // how do I get the nth element that was replaced from my template?
    // ???
    element.focus();
  }
}

How can I use the index to select a reference of the element in the view?


Solution

  • use ViewChildren and focus the last Element of the QueryList. Be carefull, It's possible you need "wait" Angular display the new data (for this use setTimeout)

    //it's 'input' because your reference variable is #input
    @ViewChildren('input',{read:ElementRef}) inputs:QueryList<ElementRef>
    
    public select_function( index) {
        this.array.splice( index, 1, {name: 'Mary'} );
        setTimeout(()=>{
            //if you want the last element
            //inputs.last.nativeElement.focus()
            //if you want the nth
            inputs.find((x,i)=>i==index).nativeElement.focus()
        })
      }