Reputation: 4789
In my demo form, fieldsets are enabled sequentially on button selection. So checking a button in first fieldset enables the second, and so on.
If all checkboxes are unchecked in the first fieldset, the form should reset and then second to fourth fieldset should be disabled again. But this is not what happens. Second fieldset somehow remains enabled. What is the problem here?
document.addEventListener("DOMContentLoaded", _ => {
const form = document.forms[0]
// First, disable all fieldsets except the first
function disableFieldsets() {
const disabledFieldsets = form.querySelectorAll(
"section:not(:first-of-type) fieldset"
)
for (let i = 0; i < disabledFieldsets.length; i++) {
disabledFieldsets[i].disabled = true
}
}
disableFieldsets()
// Sequentially enable fieldsets on selection
const sections = form.querySelectorAll("section")
sections.forEach(section => {
section.addEventListener("change", function() {
let nextFieldset = this.nextElementSibling.querySelector("fieldset")
if (nextFieldset) {
nextFieldset.disabled = false
}
})
})
// Reset form and disable fieldsets after all inputs in the first fieldset are deselected
const firstFieldsetButtons = form.querySelectorAll("[name=First]")
let isChecked = false
firstFieldsetButtons.forEach(firstFieldsetButton => {
firstFieldsetButton.addEventListener("click", function(e) {
if (this.checked) {
isChecked = true
} else {
form.reset()
disableFieldsets()
}
})
})
})
<form method=post action=submit>
<section>
<fieldset>
<legend>First Fieldset</legend>
<label><input type=checkbox name=First value=A>A</label>
<label><input type=checkbox name=First value=B>B</label>
<label><input type=checkbox name=First value=C>C</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Second Fieldset</legend>
<label><input type=radio name=Second value=1.1>1.1</label>
<label><input type=radio name=Second value=1.2>1.2</label>
<label><input type=radio name=Second value=1.3>1.3</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Third Fieldset</legend>
<label><input type=radio name=Third value=2.1>2.1</label>
<label><input type=radio name=Third value=2.2>2.2</label>
<label><input type=radio name=Third value=2.3>2.3</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Fourth Fieldset</legend>
<label><input type=radio name=Fourth value=3.1>3.1</label>
<label><input type=radio name=Fourth value=3.2>3.2</label>
<label><input type=radio name=Fourth value=3.3>3.3</label>
</fieldset>
</section>
<input type=submit value=Submit>
</form>
Upvotes: 1
Views: 179
Reputation: 122906
Just for fun, this refactoring prevents the problem @Nick Parsons described so well
const form = document.forms[0];
// one of the checkboxes checked?
const checkFirstFieldsetCheckboxes = () =>
Array.from(document.querySelector("fieldset")
.querySelectorAll("input[type=checkbox]"))
.filter(v => v.checked).length > 0;
// disable all fieldsets except the first
const disableFieldsets = () => {
form.reset();
Array.from(form.querySelectorAll("fieldset")).slice(1)
.forEach(fieldset => fieldset.disabled = true);
};
const enableNext = origin => {
const nextFieldset = origin.closest("section")
.nextElementSibling.querySelector("fieldset");
if (nextFieldset) {
nextFieldset.disabled = false;
}
};
const fieldsetHandling = evt => {
const origin = evt.target;
return !origin.type
? false
: origin.type === "radio"
? enableNext(origin)
: !checkFirstFieldsetCheckboxes()
? disableFieldsets()
: enableNext(origin);
};
// main
disableFieldsets();
// add handler (event delegation)
document.addEventListener("click", fieldsetHandling);
<form method=post action=submit>
<section>
<fieldset>
<legend>First Fieldset</legend>
<label><input type=checkbox name=First value=A>A</label>
<label><input type=checkbox name=First value=B>B</label>
<label><input type=checkbox name=First value=C>C</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Second Fieldset</legend>
<label><input type=radio name=Second value=1.1>1.1</label>
<label><input type=radio name=Second value=1.2>1.2</label>
<label><input type=radio name=Second value=1.3>1.3</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Third Fieldset</legend>
<label><input type=radio name=Third value=2.1>2.1</label>
<label><input type=radio name=Third value=2.2>2.2</label>
<label><input type=radio name=Third value=2.3>2.3</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Fourth Fieldset</legend>
<label><input type=radio name=Fourth value=3.1>3.1</label>
<label><input type=radio name=Fourth value=3.2>3.2</label>
<label><input type=radio name=Fourth value=3.3>3.3</label>
</fieldset>
</section>
<input type=submit value=Submit>
</form>
Upvotes: 1
Reputation: 5940
In your sections' change
event, instead of assigning nextFieldset
as disabled you can assign !event.target.checked
by adding event parameter to your function:
document.addEventListener("DOMContentLoaded", _ => {
const form = document.forms[0]
// First, disable all fieldsets except the first
function disableFieldsets() {
const disabledFieldsets = form.querySelectorAll(
"section:not(:first-of-type) fieldset"
)
for (let i = 0; i < disabledFieldsets.length; i++) {
disabledFieldsets[i].disabled = true
}
}
disableFieldsets()
// Sequentially enable fieldsets on selection
const sections = form.querySelectorAll("section")
sections.forEach(section => {
section.addEventListener("change", function(event) {
let nextFieldset = this.nextElementSibling.querySelector("fieldset")
if (nextFieldset) {
nextFieldset.disabled = !event.target.checked
}
})
})
// Reset form and disable fieldsets after all inputs in the first fieldset are deselected
const firstFieldsetButtons = form.querySelectorAll("[name=First]")
let isChecked = false
firstFieldsetButtons.forEach(firstFieldsetButton => {
firstFieldsetButton.addEventListener("click", function(e) {
if (this.checked) {
isChecked = true
} else {
form.reset()
disableFieldsets()
}
})
})
})
<form method=post action=submit>
<section>
<fieldset>
<legend>First Fieldset</legend>
<label><input type=checkbox name=First value=A>A</label>
<label><input type=checkbox name=First value=B>B</label>
<label><input type=checkbox name=First value=C>C</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Second Fieldset</legend>
<label><input type=radio name=Second value=1.1>1.1</label>
<label><input type=radio name=Second value=1.2>1.2</label>
<label><input type=radio name=Second value=1.3>1.3</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Third Fieldset</legend>
<label><input type=radio name=Third value=2.1>2.1</label>
<label><input type=radio name=Third value=2.2>2.2</label>
<label><input type=radio name=Third value=2.3>2.3</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Fourth Fieldset</legend>
<label><input type=radio name=Fourth value=3.1>3.1</label>
<label><input type=radio name=Fourth value=3.2>3.2</label>
<label><input type=radio name=Fourth value=3.3>3.3</label>
</fieldset>
</section>
<input type=submit value=Submit>
</form>
Upvotes: 1
Reputation: 50684
You're enabling the second fieldset every time you're changing your first fieldset - even when you are unchecking a checkbox. Even though you are disabling your fieldsets after you "click" on a checkbox, your "change"
event runs after this event, thus enabling the second fieldset. This could be fixed by using a flag to indicate whether or not the form has been reset:
document.addEventListener("DOMContentLoaded", _ => {
const form = document.forms[0];
// First, disable all fieldsets except the first
function disableFieldsets() {
const disabledFieldsets = form.querySelectorAll(
"section:not(:first-of-type) fieldset"
)
for (let i = 0; i < disabledFieldsets.length; i++) {
disabledFieldsets[i].disabled = true
}
}
disableFieldsets()
// Sequentially enable fieldsets on selection
const sections = form.querySelectorAll("section")
let reset = false;
sections.forEach(section => {
section.addEventListener("change", function() {
let nextFieldset = this.nextElementSibling.querySelector("fieldset")
if (nextFieldset && !reset) {
nextFieldset.disabled = false;
} else if(reset) {
reset = false;
}
})
})
// Reset form and disable fieldsets after all inputs in the first fieldset are deselected
const firstFieldsetButtons = form.querySelectorAll("[name=First]")
let isChecked = false;
firstFieldsetButtons.forEach(firstFieldsetButton => {
firstFieldsetButton.addEventListener("click", function(e) {
if (this.checked) {
isChecked = true;
} else {
form.reset();
disableFieldsets();
reset = true;
}
})
})
})
<form method=post action=submit>
<section>
<fieldset>
<legend>First Fieldset</legend>
<label><input type=checkbox name=First value=A>A</label>
<label><input type=checkbox name=First value=B>B</label>
<label><input type=checkbox name=First value=C>C</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Second Fieldset</legend>
<label><input type=radio name=Second value=1.1>1.1</label>
<label><input type=radio name=Second value=1.2>1.2</label>
<label><input type=radio name=Second value=1.3>1.3</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Third Fieldset</legend>
<label><input type=radio name=Third value=2.1>2.1</label>
<label><input type=radio name=Third value=2.2>2.2</label>
<label><input type=radio name=Third value=2.3>2.3</label>
</fieldset>
</section>
<section>
<fieldset>
<legend>Fourth Fieldset</legend>
<label><input type=radio name=Fourth value=3.1>3.1</label>
<label><input type=radio name=Fourth value=3.2>3.2</label>
<label><input type=radio name=Fourth value=3.3>3.3</label>
</fieldset>
</section>
<input type=submit value=Submit>
</form>
Upvotes: 1