StackBlitz here. Note the addShortcut() function is for creating the hotkeys as described below.
I am wanting to dynamically move through a form, focusing only on the invalid fields, but allowing the user to traverse through these invalid fields as necessary.
For example, if I have a form where the address, phone, and email inputs are the only required fields, the user can push a button and cycle through these specific fields.
Now, say they are moving through the 3 fields, and they fill in the address field. This is no longer invalid, so now the form should loop/cycle through the phone and email input fields only.
I am using a custom hotkey function so that when a user presses alt + a, the focus is set. The user can press this again, and focus goes to the next required field.
When the app is run ngOnInit() builds the form, and triggers a function to find invalid fields:
findInvalidFields() {
this.invalidFields = [];
const controls = this.myForm.controls;
for (const name in controls) {
if (controls[name].invalid) {
this.invalidFields.push(name);
}
}
}
this.invalidFields is now an array of only the invalid fields:
[
"customerAddress",
"customerPhone",
"customerEmail"
]
The hotkey is pressed, and I run a function to set the focus, then shift the array so it goes to the next invalid item.:
... {
this.setFocus(this.invalidFields[0]);
this.invalidFields.push(this.invalidFields.shift());
}
The problem is now even if I fill in a form, the focus will move back and forth through the entire original list -- this is expected because the invalid fields are only being found OnInit... Of course, I can run findInvalidFields() every time the hotkey is pressed, so my hotkey function looks like this:
... {
this.findInvalidFields();
this.setFocus(this.invalidFields[0]);
this.invalidFields.push(this.invalidFields.shift());
}
This works in getting the correct invalid fields, but no longer "cycles" through the invalid fields since the form returns a specific order of controls each time the function is run therefore getting stuck on an input until it is no longer invalid.
Is there a way to dynamically "cycle" through the input fields without getting "stuck" on invalid fields?
Here is my quick-and-dirty solution. It can likely be cleaned up quite a bit but it seems to work.
First we need to listen for the relevant keypress and fire our function to update the focus, I used the right arrow key to simplify it a bit,
Then the focusNext() function looks like this,
Where this.formFocus is a field that we use to track the actively focused form control,
Then in your template you will need to bind the (focus) event on each of your inputs to
onControlFocus()and pass in theformcontrolnameof the input,Most of this solution is inside the focusNext() function and the way I stored the first invalid control is a little messy. If you wanted to clean it up you could try storing the form controls in a circularly linked list that would let you iterate right back to the first invalid element. That way you could avoid some of the tracking variables.