简体   繁体   中英

Angular : When submitting Template Driven form how can I set focus on first invalid input

I have checked in stackoverflow but I only found the way to do. I found a solution with querySelector but is there any better approach for setting focus? When I submit the form then I want to set focus on the first invalid input using Template Driven form.

How can I set focus on first invalid input using Template Driven forms?

SOLUTION # 1:

I just coded this and it's working at least with inputs (with type text and number) and also with selects. It's using template driven as you requested.

Here it goes:

This is the minimum that you will need in your component (.ts file):

// Built-in Packages:
import { Component, ElementRef, ViewChild } from '@angular/core';
import { NgForm } from "@angular/forms";

@Component({
  selector: 'app-shopping-edit',
  templateUrl: './shopping-edit.component.html',
  styleUrls: ['./shopping-edit.component.css']
})
export class ShoppingEditComponent implements OnInit {
  @ViewChild('f', {static: false}) ingredientForm: NgForm;

  constructor(private elementRef: ElementRef) {
  }

  focusFirstInvalidControl(): void {
    const formControls = this.ingredientForm.controls;
    const formControlsKeys = Object.keys(formControls)

    for (let i = 0; i < formControlsKeys.length; i++) {
      const isInvalid = formControls[formControlsKeys[i]].invalid;
      if (isInvalid) {
        this.elementRef.nativeElement.querySelector(`#${formControlsKeys[i]}`).focus();
        break;
      }
    }
  }
}

That NgForm is connected as usual to your form on your template.

Conditions:

in order to make this work, each input inside the form in your template, needs to have a matching id, with the name and the local reference bindded to ngModel. All of them using the same name/denomination.

Example: Using a text input for the " Name ".

      <div class="form-group">
        <label for="name">Name</label>
        <input
          type="text"
          id="name"
          name="name"
          class="form-control"
          placeholder="Type the name here"
          autofocus
          required
          ngModel
          #name="ngModel"
        >
      </div>
      <span *ngIf="(name?.invalid && name.touched); else nameOk" class="help-block">Please enter a valid name</span>
      <ng-template #nameOk><span class="help-block">&nbsp;</span></ng-template>
    </div>

Another example: Using a numeric input for the " Amount ":

      <div class="form-group">
        <label for="amount">Amount</label>
        <input
          type="number"
          id="amount"
          name="amount"
          min="1"
          class="form-control"
          required
          [ngModel]="1"
          #amount="ngModel"
        >

      </div>
      <span *ngIf="(amount?.invalid && amount.touched); else amountOk" class="help-block">Please enter a valid amount</span>
      <ng-template #amountOk><span class="help-block">&nbsp;</span></ng-template>

Now you only need to trigger the method " focusFirstInvalidControl " on the submit event or by any other way that you prefer.

SOLUTION # 2:

This is even simpler:

  constructor(private elementRef: ElementRef) {
  }

      focusFirstInvalidControlPlus(): void {
        const firstElementWithErrors: HTMLElement = this.elementRef.nativeElement.querySelector(`form .ng-invalid`);
        if (firstElementWithErrors) {
          firstElementWithErrors.focus();
        }
      }

Just trigger the method " focusFirstInvalidControlPlus " within your .ts file on the submit event. It works when using template driven and also with Reactive approach.

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