Javascript 角度6反应形式:如何设置第一个无效输入的焦点

Javascript 角度6反应形式:如何设置第一个无效输入的焦点,javascript,angular,html,rxjs,angular-reactive-forms,Javascript,Angular,Html,Rxjs,Angular Reactive Forms,在我的Angular 6应用程序下,我正在使用反应式表单 我的目的是在提交时,我想在出现错误时将焦点设置在第一个无效输入上 我的表单如下所示: 我尝试了自动对焦指令,但没有成功 建议?我的答案来源于这里的。我使用他回答中的逻辑,通过使用FormControl获取特定FormControl的nativeElement 这就是这样做的逻辑: const originFormControlNameNgOnChanges = FormControlName.prototype.ngOnChanges;

在我的Angular 6应用程序下,我正在使用反应式表单

我的目的是在提交时,我想在出现错误时将焦点设置在第一个无效输入上

我的表单如下所示:

我尝试了自动对焦指令,但没有成功


建议?

我的答案来源于这里的。我使用他回答中的逻辑,通过使用
FormControl
获取特定
FormControl
nativeElement

这就是这样做的逻辑:

const originFormControlNameNgOnChanges = FormControlName.prototype.ngOnChanges;
FormControlName.prototype.ngOnChanges = function () {
  const result = originFormControlNameNgOnChanges.apply(this, arguments);
  this.control.nativeElement = this.valueAccessor._elementRef.nativeElement;
  return result;
};
现在,表单的errors字段将为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;
    }
  }
}
<form [formGroup]="userForm" (submit)="saveData()" appFocus >
...
</form>
onSubmitForm(){
常量字段STOCHECK=[
“codeBasicat”,
“诽谤”,
“无应用程序”
];
for(设i=0;ithis.additemform.get(fieldName)).nativeElement.focus();
打破
}
}
}
我故意使用
for
而不是
Array.forEach
,因为我想打破循环

希望这能帮到你

这是给你的裁判的一封信


我是用指令做的。因此,我的表单如下所示:

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;
    }
  }
}
<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();
    }
  }
}
import{Directive,HostListener,Input,ElementRef}来自“@angular/core”;
从'@angular/forms'导入{NgForm};
@指示({
选择器:“[appFocus]”
})
导出类FocusDirective{
构造函数(私有el:ElementRef){}
@Input()formGroup:NgForm;
@HostListener('提交',['$event']))
公开提交(事件):无效{
if('INVALID'==this.formGroup.status){
event.preventDefault();
const formGroupInvalid=this.el.nativeElement.querySelectorAll('.ng invalid');
(formGroupInvalid[0]).focus();
}
}
}

然而,这个解决方案是不完整的,因为有很多角落的情况,必须加以考虑。例如,如果第一个元素是单选按钮组,该怎么办。调度焦点事件将自动标记该字段。第二,不是所有angular ads ng invalid的元素都将成为输入。

此选项对我不起作用,但我通过如下更改代码来修复它:

@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();
    }
  }

}
试试这个:

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是否不是我遇到的您自己的表单,所以请正确查看它作为第一个字段报告的字段,并纠正位置。

我们只需在表单的submit()中编写此代码,就可以将焦点设置在第一个无效输入上

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

    }

在提交时使用以下代码

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;
     }
}
此.addressForm将成为您的FormGroup


这里甚至不需要指令。

我需要动态获取第一个出错输入的引用,并将焦点设置为it@firasKoubaa,我已经更新了我的答案。请检查一下这对你是否有效。我还添加了一个工作示例StackBlitz,您可能想看看。希望这会有帮助。@SiddAjmera您可以用来中断:)不过,我想查找DOM顺序中的第一个无效字段…querySelectorAll()返回一个NodeListOf,元素类型没有焦点()method@TheCodeFox对我来说,它起作用了,请检查您使用的是哪个版本,哪个是这个的类型。el?添加“private el:ElementRef”对于你的构造器(ElementRef格式'@angular/core'),它对我有效,但只对输入字段有效,对下拉字段无效。