循环遍历表单,关注必填(但无效)字段

Posted

技术标签:

【中文标题】循环遍历表单,关注必填(但无效)字段【英文标题】:Loop Through a Form, Focusing on Required (yet invalid) Fields 【发布时间】:2021-09-22 00:40:41 【问题描述】:

StackBlitz here. 注意addShortcut() 函数用于创建如下所述的热键。

我想动态移动表单,只关注无效字段,但允许用户根据需要遍历这些无效字段。

例如,如果我有一个表单,其中 addressphoneemail 输入是唯一的必填字段,则用户可以按下按钮并循环浏览这些特定字段。

现在,假设他们正在浏览 3 个字段,并填写 address 字段。这不再无效,所以现在表单应该循环/循环通过 phoneemail 输入字段。

我正在使用自定义热键功能,这样当用户按下alt + a 时,焦点就会被设置。用户可以再按一次,焦点转到下一个必填字段。

当应用程序运行时ngOnInit() 构建表单,并触发一个函数来查找无效字段:

findInvalidFields() 
  this.invalidFields = [];
  const controls = this.myForm.controls;

  for (const name in controls) 
    if (controls[name].invalid) 
      this.invalidFields.push(name);
    
  

this.invalidFields 现在是一个仅包含无效字段的数组:

[
  "customerAddress",
  "customerPhone",
  "customerEmail"
]

按下热键,然后我运行一个函数来设置焦点,然后移动数组使其转到下一个无效项。:

... 
  this.setFocus(this.invalidFields[0]);
  this.invalidFields.push(this.invalidFields.shift());

现在的问题是,即使我填写表格,焦点也会在整个原始列表中来回移动——这是意料之中的,因为仅在 OnInit 中找到无效字段...当然,我可以运行findInvalidFields()每次按下热键,所以我的热键功能是这样的:

... 
  this.findInvalidFields();
  this.setFocus(this.invalidFields[0]);
  this.invalidFields.push(this.invalidFields.shift());

这有助于获取正确的无效字段,但不再“循环”通过无效字段,因为每次运行函数时表单都会返回特定的控件顺序,因此会卡在输入上,直到它不再无效。

有没有办法在输入字段中动态“循环”而不会“卡在”无效字段上?

Stackblitz.

【问题讨论】:

【参考方案1】:

这是我的快速而肮脏的解决方案。它可能会被清理很多,但它似乎有效。

首先我们需要监听相关的按键并触发我们的函数来更新焦点,我使用右箭头键来简化它,

  @HostListener('window:keyup', ['$event'])
  keyEvent(event: KeyboardEvent) 
    if (event.key === 'ArrowRight') 
      this.focusNext();
    
  

那么focusNext()函数是这样的,

  private focusNext(): void 
    let focusNextControl: boolean = false;
    let focusSet: boolean = false;
    let firstKey: string;

    let currentControlInvalid: boolean;
    Object.keys(this.myForm.controls).forEach((key, index) => 
      currentControlInvalid = this.myForm.controls[key].invalid;
      //Find the first invalid control, we will need it later in the case that the active focus is on the last control on the form
      if(!firstKey && currentControlInvalid)
        firstKey = key;
      
      //If the current control is invalid 
      //AND the previous control is the currently focused one 
      //AND we haven't already set the focus.. Then set the focus on this control.
      if(currentControlInvalid && focusNextControl && !focusSet)
        this.elRef.nativeElement.querySelector('[formcontrolname = "' + key + '"]').focus();
        focusSet = true;
      
      else if(this.myForm.controls[key] == this.formFocus)
        focusNextControl = true;
      
      else if(!focusSet && focusNextControl && index == Object.keys(this.myForm.controls).length - 1)
        //If we are on the last control and we need to set the 'next' control 
        //AND we haven't already focused on a control
        //Then we need to set the focus to the first invalid control we found
        this.elRef.nativeElement.querySelector('[formcontrolname = "' + firstKey + '"]').focus();
      
    );
  

其中 this.formFocus 是我们用来跟踪主动聚焦的表单控件的字段,

  private formFocus: FormControl;
  public onControlFocus(control: string): void 
    this.formFocus = this.myForm.controls[control] as FormControl;
  

然后在您的模板中,您需要将每个输入上的(焦点)事件绑定到onControlFocus() 并传入输入的formcontrolname

    <input
        formControlName="firstName" 
        type="text" class="form-control" id="firstName"
        (focus)="onControlFocus('firstName')"
    >

这个解决方案的大部分都在 focusNext() 函数内部,而我存储第一个无效控件的方式有点混乱。如果您想清理它,您可以尝试将表单控件存储在循环链接列表中,这样您就可以直接迭代回第一个无效元素。这样可以避免一些跟踪变量。

【讨论】:

以上是关于循环遍历表单,关注必填(但无效)字段的主要内容,如果未能解决你的问题,请参考以下文章

使用ajax将它们作为json后如何循环遍历django表单错误

遍历具有不同索引的表单元素名称数组

从收集循环中获取表单字段值

关注表单时如何更改表单中输入标签的颜色? [复制]

Django:For循环迭代表单字段

循环遍历表单上所有未绑定的控件并清除数据