I want to partially validate a form by validating all elements inside a fieldset.
As a trigger for that validation, I'm listening to focusout
events which bubble up to each fieldset.
I want to perform the validation if no form element inside that fieldset has :focus
.
I've attempted to do like this:
const fieldsets = [...document.querySelectorAll('fieldset')]
for (const fieldset of fieldsets) {
fieldset.addEventListener('focusout', (e) => {
let focussedElements = e.currentTarget.querySelectorAll(':focus');
if (focussedElements.length === 0) {
console.log(`no element inside fieldset #${e.currentTarget.id} has focus`)
} else if (focussedElements.length > 0) {
console.log(`element ${focussedElements[0]} inside fieldset #${e.currentTarget.id} has focus`)
}
})
}
<fieldset id="fs1">
<legend>Fieldset 1</legend>
<input type="text">
<input type="text">
</fieldset>
<fieldset id="fs2">
<legend>Fieldset 2</legend>
<input type="text">
<select>
<option>1</option>
<option>2</option>
</select>
</fieldset>
but e.currentTarget.querySelectorAll(':focus')
always has length
of 0
.
How do I reliably check if a fieldset
has a child element that has :focus
?
Note: I don't want to use jQuery or any other library for the task.
Don't you just need to wait for the focus on the new element to happen? Like this:
const fieldsets = [...document.querySelectorAll('fieldset')]
for (const fieldset of fieldsets) {
fieldset.addEventListener('focusout', (e) => {
let ct = e.currentTarget;
setTimeout(() => {
let focussedElements = ct.querySelectorAll(':focus');
if (focussedElements.length === 0) {
console.log(`no element inside fieldset #${ct.id} has focus`)
} else if (focussedElements.length > 0) {
console.log(`element ${focussedElements[0]} inside fieldset #${ct.id} has focus`)
}
}, 10)
})
}
<fieldset id="fs1">
<legend>Fieldset 1</legend>
<input type="text">
<input type="text">
</fieldset>
<fieldset id="fs2">
<legend>Fieldset 2</legend>
<input type="text">
<select>
<option>1</option>
<option>2</option>
</select>
</fieldset>