简体   繁体   English

Angular 6 反应式 Forms:如何将焦点设置在第一个无效输入上

[英]Angular 6 Reactive Forms : How to set focus on first invalid input

Under my Angular 6 app, i'm using Reactive Forms .在我的Angular 6应用程序下,我使用的是反应式 Forms

My purpose is when submitting, i want to set focus on first invalid input when error.我的目的是在提交时,我想在出错时将焦点放在第一个无效输入上。

My form looks like this:我的表格如下所示:

 <form [formGroup]="addItemfForm " (ngSubmit)="onSubmitForm()"> <div class="form-inline form-group"> <label class="col-md-2 justify-content-start"> Libellé du pef <span class="startRequired mr-1"> *</span> </label> <input type="text" maxlength="100" formControlName="libellePef" class="col-md-6 form-control" placeholder="saisie obligatoire" [ngClass]="{ 'is-invalid': submitted && formFiels.libellePef.errors }" /> <div *ngIf="submitted && formFiels.libellePef.errors" class="col invalid-feedback"> <div class="col text-left" *ngIf="formFiels.libellePef.errors.required">Libellé du pef est requis.</div> </div> </div> <div class="form-inline form-group"> <label class="col-md-2 justify-content-start"> Code Basicat <span class="startRequired mr-1"> *</span> </label> <input type="text" maxlength="100" formControlName="codeBasicat" class="col-md-3 form-control" placeholder="saisie obligatoire" [ngClass]="{ 'is-invalid': submitted && formFiels.codeBasicat.errors }" /> <div *ngIf="submitted && formFiels.codeBasicat.errors" class="col invalid-feedback"> <div class="text-left" *ngIf="formFiels.codeBasicat.errors.required">Code Basicat est requis.</div> </div> </div> <div class="form-inline form-group"> <label class="col-md-2 justify-content-start"> Nom de l'application <span class="startRequired mr-1"> *</span> </label> <input type="text" maxlength="100" formControlName="nomApplication" class="col-md-6 form-control" placeholder="saisie obligatoire" [ngClass]="{ 'is-invalid': submitted && formFiels.nomApplication.errors }" /> <div *ngIf="submitted && formFiels.nomApplication.errors" class="col invalid-feedback"> <div class="text-left" *ngIf="formFiels.nomApplication.errors.required">Nom de l'application est requis. </div> </div> </div> </form>

Under my TS file, my form config looks like this:在我的 TS 文件下,我的表单配置如下所示:

 this.addItemfForm = this.formBuilder.group({ libellePef: ['', Validators.required], codeBasicat: ['', Validators.required ], nomApplication: ['', Validators.required ], urlCible: [''], modeTransfert: [''], });

I've tried the autofocus directive but that didn't work我已经尝试了自动对焦指令,但没有奏效

Suggestions?建议?

Use below code in your submit.在您的提交中使用以下代码。

 for (const key of Object.keys(this.addressForm.controls)) { if (this.addressForm.controls[key].invalid) { const invalidControl = this.el.nativeElement.querySelector('[formcontrolname="' + key + '"]'); invalidControl.focus(); break; } }

this.addressForm will be your FormGroup. this.addressForm 将是您的 FormGroup。

We don't even need directive here.我们在这里甚至不需要指令。

My Answer is inspired from yurzui 's answer here.我的答案的灵感来自yurzui答案 I'm using the logic from his answer to get the nativeElement of a particular FormControl by using it's FormControl .我正在使用他的回答中的逻辑来获取特定FormControlnativeElement ,方法是使用它的FormControl

This is the logic that does that:这是这样做的逻辑:

 const originFormControlNameNgOnChanges = FormControlName.prototype.ngOnChanges; FormControlName.prototype.ngOnChanges = function () { const result = originFormControlNameNgOnChanges.apply(this, arguments); this.control.nativeElement = this.valueAccessor._elementRef.nativeElement; return result; };

Now, the form's errors field would be null even though it's fields are invalid.现在,表单的错误字段将是 null,即使它的字段无效。 So to get the exact first field that's invalid, we'll have to loop through all the fields and check for validity for each of them.因此,要获得确切的第一个无效字段,我们必须遍历所有字段并检查每个字段的有效性。 I can write this logic in the onSubmitForm() method.我可以在onSubmitForm()方法中编写这个逻辑。 Something like this:像这样的东西:

 onSubmitForm() { const fieldsToCheck = [ 'codeBasicat', 'libellePef', 'nomApplication' ]; for (let i = 0; i < fieldsToCheck.length; i++) { const fieldName = fieldsToCheck[i]; if (this.addItemfForm.get(fieldName).invalid) { ( < any > this.addItemfForm.get(fieldName)).nativeElement.focus(); break; } } }

I've deliberately used for instead of Array.forEach as I wanted to break from the loop.我故意使用for而不是Array.forEach因为我想打破循环。

Hopefully this should do the trick for you.希望这对你有用。

Here's a Working Sample StackBlitz for your ref.这是您参考的工作示例 StackBlitz

I did that using directives.我使用指令做到了这一点。 So My form would look like this:所以我的表格看起来像这样:

 <form [formGroup]="userForm" (submit)="saveData()" appFocus >... </form>

and the code for the directive itself:以及指令本身的代码:

 import { Directive, HostListener, Input, ElementRef } from '@angular/core'; import { NgForm } from '@angular/forms'; @Directive({ selector: '[appFocus]' }) export class FocusDirective { constructor(private el: ElementRef) { } @Input() formGroup: NgForm; @HostListener('submit', ['$event']) public onSubmit(event): void { if ('INVALID' === this.formGroup.status) { event.preventDefault(); const formGroupInvalid = this.el.nativeElement.querySelectorAll('.ng-invalid'); (<HTMLInputElement>formGroupInvalid[0]).focus(); } } }

However this solution is incomplete as there is a lot of corner cases that have to be considered.然而,这个解决方案是不完整的,因为需要考虑很多极端情况。 For example what if the first element is radio button group.例如,如果第一个元素是单选按钮组怎么办。 Dispatching focus event will automatically mark the filed.调度焦点事件将自动标记归档。 Second not every element to which angular ads ng-invalid will be an input.其次,并非 angular ads ng-invalid 将作为输入的每个元素。

We can set focus on first invalid input simply by just write this code in the submit() of the form.我们只需在表单的 submit() 中编写此代码即可将焦点设置在第一个无效输入上。

 if(this.form.invalid) { // Got focus to the error field let invalidFields = [].slice.call(document.getElementsByClassName('ng-invalid')); invalidFields[1].focus(); }

Try this:尝试这个:

 import { Directive, HostListener, ElementRef} from '@angular/core'; @Directive({ selector: '[focusFirstInvalidField]' }) export class FocusFirstInvalidFieldDirective { constructor(private el: ElementRef) { } @HostListener('submit') onFormSubmit() { const invalidElements = this.el.nativeElement.querySelectorAll('.ng-invalid'); if (invalidElements.length > 0) { console.log(invalidElements[0]); invalidElements[0].focus(); } } }

Remember to debug, see if element 0 is not your own form as it happened to me, so see right what field it is reporting as the first and put the position right.记得调试,看看元素 0 是否不是你自己的表单,因为它发生在我身上,所以看看它报告的第一个字段是什么,然后把 position 放在右边。

This option does not work for me, but I managed to fix it by changing the code as follows:此选项对我不起作用,但我设法通过更改代码来修复它,如下所示:

 @Directive({ selector: '[appErrorFocusin]' }) export class ErrorFocusinDirective { selectorToFocus: String = 'textArea,mat-select,select,input,button'; constructor(private el: ElementRef, @Inject(DOCUMENT) private document: Document) { } @Input() formGroup: NgForm; @HostListener('submit', ['$event']) public onSubmit(event): void { if ('INVALID' === this.formGroup.status) { event.preventDefault(); const formGroupInvalid = this.el.nativeElement.querySelectorAll('.ng- invalid,:not(.mat-badge-hidden).mat-badge'); let elementToOffset = this.getElementToOffset(formGroupInvalid[0]); this.document.documentElement.scrollTop = elementToOffset.offsetTop; this.setFocusOnError(elementToOffset); } } getElementToOffset(element: any){ let defaultElement = element; while (.(element.parentElement instanceof HTMLFormElement)){ if (element.parentElement){ element = element;parentElement; }else{ return defaultElement; } } return element: } setFocusOnError(elementToOffset. any){ let listaElementos = elementToOffset.querySelectorAll(this;selectorToFocus). if (listaElementos.length>0){ listaElementos[0];focus() } } }

A continuation to @Avinash's answer, instead of making it @Avinash 答案的延续,而不是做出来

querySelector('[formcontrolname="' + key + '"]');

We can add id's in the HTML to the input and simply make that as this:我们可以将 HTML 中的 id 添加到输入中,然后简单地如下所示:

 querySelector('#'+ key +'.ng-invalid');

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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