Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular, how to set focus in a specific FormControl of FormArray

Tags:

lHow ca I set focus to a specific field in a formArray?

this is the formArray:

    this.productForm = this.formBuilder.array([
     this.formBuilder.group({
     code: [null],
     description: [null],
     unitPrice: [null],
     qty: [null],
     discount: [null],
     vat: [null],
     total: [null],
     amount: [null],
     taxAmount: [null]
  })
]);

I can have a lot of this formGroup and I need to focus a specific description field. Is there a smart way in angular?

like image 525
Alessandro Celeghin Avatar asked Nov 21 '18 13:11

Alessandro Celeghin


2 Answers

If you know the specific item you want to focus it would be fairly straightforward first of all by adding a template reference:

<input
  #fieldName
  type="text"
  id="fieldName"
  name="fieldName"
  formControlName="yourFieldName" />

Then in your component (probably in ngAfterViewInit() method):

@ViewChild('fieldName') fieldName: ElementRef;

Then to focus on your element:

this.fieldName.nativeElement.focus();

NB this will be vulnerable to XSS attacks though

like image 72
rrd Avatar answered Nov 15 '22 12:11

rrd


Had this same issue. I resolved it by rethinking the implementation.

My situation was that I wanted to focus on the row (first input) when the use tabbed (blurred) out of the last row. I had implemented a directive to handle the blur and focus on my Row.

import { Directive, Input, Output, ElementRef, EventEmitter, HostListener, HostBinding } from '@angular/core';

@Directive({
  selector: '[focusedRow]'
})
export class RowDirective {
  static tabindex = 1;
  static currentFocus = null;

  private timer: any = null;

  @HostBinding('tabindex') public tabIndex: number = 0;

  @Input('formGroupName') public rowNumber: number;

  @Output('focus') public onFocus: EventEmitter<number> = new EventEmitter<number>();
  @Output('blur')  public onBlur: EventEmitter<number> = new EventEmitter<number>();

  constructor(private elm: ElementRef) {
    this.tabIndex = RowDirective.tabindex++;
  }

  @HostListener('focusin', ['$event'])
  public focusHandler(event: Event) {
    // When we're not the current focus.
    if (RowDirective.currentFocus !== this) {
      this.onFocus.emit(event);

      RowDirective.currentFocus = this;

    } else {
      // Stop our blur from happening since it's the same row
      if (this.timer) {
        window.clearTimeout(this.timer);
        this.timer = null;
      }
    }
  }
  @HostListener('focusout', ['$event'])
  public blurHandler(event: Event) {
    this.timer = window.setTimeout(() => {
      // If our row has changed, then we have blurred.
      this.onBlur.emit(event);

      // Clear if this is still listed as the Focused Row.
      if (RowDirective.currentFocus === this) {
        RowDirective.currentFocus = null;
      }
    }, 200);
  }
}

What I did was, instead of trying to battle the Angular Form Group, I simply made it that when a new Row was created from my Reactive Form and the row was added, because the form row element had the directive applied, the better solution was to simply focus the row (first input) when the directive initialised.

This was done using the OnInit interface. So the above code was adjusted to include the interface (changes below);

import { Directive, Input, Output, OnInit, ElementRef, EventEmitter, HostListener, HostBinding } from '@angular/core';

@Directive({
  selector: '[focusedRow]'
})
export class RowDirective implements OnInit {
  ....

  ngOnInit() {
    // Focus on the first Form Element
    this.elm.nativeElement.querySelector('input').focus();
  }

  ....
}

So create the above Directive, and then add that directive to your Form Array element...

 <tr *ngFor="let entry of myForms.controls; let index=index" [formGroupName]="index" focusedRow (focus)="rowFocus(index)" (blur)="rowBlur(index)">

This way, anytime a row is created, it focuses the first form element.

The beauty of this solution is that it also works when the user clicked my "Add new Row" button, and you get some cool Focus and Blur handlers on your [table] row. (the secret to that by the way is the use of the tabindex attribute)

Hope that helps your situation.

like image 30
Guy Park Avatar answered Nov 15 '22 12:11

Guy Park