[英]Angular 6 Reactive Forms : How to set focus on first invalid input
在我的Angular 6应用程序下,我使用的是反应式 Forms 。
我的目的是在提交时,我想在出错时将焦点放在第一个无效输入上。
我的表格如下所示:
<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>
在我的 TS 文件下,我的表单配置如下所示:
this.addItemfForm = this.formBuilder.group({ libellePef: ['', Validators.required], codeBasicat: ['', Validators.required ], nomApplication: ['', Validators.required ], urlCible: [''], modeTransfert: [''], });
我已经尝试了自动对焦指令,但没有奏效
建议?
在您的提交中使用以下代码。
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 将是您的 FormGroup。
我们在这里甚至不需要指令。
我的答案的灵感来自yurzui的答案。 我正在使用他的回答中的逻辑来获取特定FormControl
的nativeElement
,方法是使用它的FormControl
。
这是这样做的逻辑:
const originFormControlNameNgOnChanges = FormControlName.prototype.ngOnChanges; FormControlName.prototype.ngOnChanges = function () { const result = originFormControlNameNgOnChanges.apply(this, arguments); this.control.nativeElement = this.valueAccessor._elementRef.nativeElement; return result; };
现在,表单的错误字段将是 null,即使它的字段无效。 因此,要获得确切的第一个无效字段,我们必须遍历所有字段并检查每个字段的有效性。 我可以在onSubmitForm()
方法中编写这个逻辑。 像这样的东西:
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; } } }
我故意使用for
而不是Array.forEach
因为我想打破循环。
希望这对你有用。
这是您参考的工作示例 StackBlitz 。
我使用指令做到了这一点。 所以我的表格看起来像这样:
<form [formGroup]="userForm" (submit)="saveData()" appFocus >... </form>
以及指令本身的代码:
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(); } } }
然而,这个解决方案是不完整的,因为需要考虑很多极端情况。 例如,如果第一个元素是单选按钮组怎么办。 调度焦点事件将自动标记归档。 其次,并非 angular ads ng-invalid 将作为输入的每个元素。
我们只需在表单的 submit() 中编写此代码即可将焦点设置在第一个无效输入上。
if(this.form.invalid) { // Got focus to the error field let invalidFields = [].slice.call(document.getElementsByClassName('ng-invalid')); invalidFields[1].focus(); }
尝试这个:
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(); } } }
记得调试,看看元素 0 是否不是你自己的表单,因为它发生在我身上,所以看看它报告的第一个字段是什么,然后把 position 放在右边。
此选项对我不起作用,但我设法通过更改代码来修复它,如下所示:
@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() } } }
@Avinash 答案的延续,而不是做出来
querySelector('[formcontrolname="' + key + '"]');
我们可以将 HTML 中的 id 添加到输入中,然后简单地如下所示:
querySelector('#'+ key +'.ng-invalid');
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.