循环遍历表单,关注必填(但无效)字段
Posted
技术标签:
【中文标题】循环遍历表单,关注必填(但无效)字段【英文标题】:Loop Through a Form, Focusing on Required (yet invalid) Fields 【发布时间】:2021-09-22 00:40:41 【问题描述】:StackBlitz here. 注意addShortcut()
函数用于创建如下所述的热键。
我想动态移动表单,只关注无效字段,但允许用户根据需要遍历这些无效字段。
例如,如果我有一个表单,其中 address
、phone
和 email
输入是唯一的必填字段,则用户可以按下按钮并循环浏览这些特定字段。
现在,假设他们正在浏览 3 个字段,并填写 address
字段。这不再无效,所以现在表单应该循环/循环通过 phone
和 email
输入字段。
我正在使用自定义热键功能,这样当用户按下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() 函数内部,而我存储第一个无效控件的方式有点混乱。如果您想清理它,您可以尝试将表单控件存储在循环链接列表中,这样您就可以直接迭代回第一个无效元素。这样可以避免一些跟踪变量。
【讨论】:
以上是关于循环遍历表单,关注必填(但无效)字段的主要内容,如果未能解决你的问题,请参考以下文章