Reputation: 6663
HTML5 form validation will not cover the situation where, starting from a group of checkboxes, at least one of them is checked. If a checkbox has the required attribute it must be checked, this is what I can get at most. So I built a workaround that works fine (code in the snippet). The issue is that this works for one group of checkboxes. But I want my code to be valid even if I add more chackboxes groups. I need a suggestion on how to make it valid for multiple groups. Any idea?
function bindItemsInput() {
var inputs = document.querySelectorAll('[name="option[]"]')
var radioForCheckboxes = document.getElementById('radio-for-checkboxes')
function checkCheckboxes () {
var isAtLeastOneServiceSelected = false;
for(var i = inputs.length-1; i >= 0; --i) {
if (inputs[i].checked) isAtLeastOneCheckboxSelected = true;
}
radioForCheckboxes.checked = isAtLeastOneCheckboxSelected
}
for(var i = inputs.length-1; i >= 0; --i) {
inputs[i].addEventListener('change', checkCheckboxes)
}
}
bindItemsInput() // call in window onload
.checkboxs-wrapper {
position: relative;
}
.checkboxs-wrapper input[name="radio-for-required-checkboxes"] {
position: absolute;
margin: 0;
top: 0;
left: 0;
width: 100%;
height: 100%;
-webkit-appearance: none;
pointer-events: none;
border: none;
background: none;
}
<form>
<div class="checkboxs-wrapper">
<input id="radio-for-checkboxes" type="radio" name="radio-for-required-checkboxes" required/>
<input type="checkbox" name="option[]" value="option1"/>
<input type="checkbox" name="option[]" value="option2"/>
<input type="checkbox" name="option[]" value="option3"/>
</div>
<input type="submit" value="submit"/>
</form>
A second snippet with the relevant HTML (not working, goal of the question is to fix this). It will have now the same ID for the radio button: that is invalid and is the reason of the question:
function bindItemsInput() {
var inputs = document.querySelectorAll('[name="option[]"]')
var radioForCheckboxes = document.getElementById('radio-for-checkboxes')
function checkCheckboxes () {
var isAtLeastOneServiceSelected = false;
for(var i = inputs.length-1; i >= 0; --i) {
if (inputs[i].checked) isAtLeastOneCheckboxSelected = true;
}
radioForCheckboxes.checked = isAtLeastOneCheckboxSelected
}
for(var i = inputs.length-1; i >= 0; --i) {
inputs[i].addEventListener('change', checkCheckboxes)
}
}
bindItemsInput() // call in window onload
.checkboxs-wrapper {
position: relative;
}
.checkboxs-wrapper input[name="radio-for-required-checkboxes"] {
position: absolute;
margin: 0;
top: 0;
left: 0;
width: 100%;
height: 100%;
-webkit-appearance: none;
pointer-events: none;
border: none;
background: none;
}
<form>
<div class="checkboxs-wrapper">
<input id="radio-for-checkboxes" type="radio" name="radio-for-required-checkboxes" required/>
<input type="checkbox" name="option[]" value="option1"/>
<input type="checkbox" name="option[]" value="option2"/>
<input type="checkbox" name="option[]" value="option3"/>
</div>
<div class="checkboxs-wrapper">
<input id="radio-for-checkboxes" type="radio" name="radio-for-required-checkboxes" required/>
<input type="checkbox" name="products[]" value="option1"/>
<input type="checkbox" name="products[]" value="option2"/>
<input type="checkbox" name="products[]" value="option3"/>
</div>
<input type="submit" value="submit"/>
</form>
The form will be valid if at least on products[] checkbox and one option[] checkbox is checked. So I need the javascript to run indipendently for option[] and for products[]. If I have selected one item in groups[] but none in products[] then only products will be surrounded by the box and marked for completition
Upvotes: 0
Views: 181
Reputation: 6683
Using jQuery this can be done with a lot less code.
$(document).ready(function() {
var checkCheckboxesInSameGroup = function() {
var inputs = $(this).children("input[name='option[]']");
var radio = $(this).children("input[name^='radio-for-group']")[0];
radio.checked = inputs.is(":checked");
};
$(".checkboxs-wrapper").on('change', checkCheckboxesInSameGroup);
});
.checkboxs-wrapper {
position: relative;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<div class="checkboxs-wrapper">
<input type="radio" name="radio-for-group1" required/>
<input type="checkbox" name="option[]" value="option1"/>
<input type="checkbox" name="option[]" value="option2"/>
<input type="checkbox" name="option[]" value="option3"/>
</div>
<div class="checkboxs-wrapper">
<input type="radio" name="radio-for-group2" required/>
<input type="checkbox" name="option[]" value="option1"/>
<input type="checkbox" name="option[]" value="option2"/>
<input type="checkbox" name="option[]" value="option3"/>
</div>
</form>
Upvotes: 0
Reputation: 22265
So this what I imagine you are looking for:
const myForm = document.forms['my-form']
myForm.addEventListener('change', bindItemsInput) // global change event listener
function bindItemsInput(e) //
{
if (!e.target.matches('div.checkboxs-wrapper input[type=checkbox]')) return
// to reject unconcerned checkbox
let groupDiv = e.target.closest('div.checkboxs-wrapper')
, radioGroup = groupDiv.querySelector('input[type=radio]')
, checkGroup = groupDiv.querySelectorAll('input[type=checkbox]')
;
radioGroup.checked = [...checkGroup].reduce((flag,chkBx)=>flag || chkBx.checked, false)
}
// ------ verification part-------------------
myForm.onsubmit=e=> // to verify
{
e.preventDefault() // disable submit for testing
console.clear()
// chexboxes checked values:
let options = [...myForm['option[]'] ].reduce((r,s)=>{ if (s.checked) r.push(s.value);return r},[])
, products = [...myForm['product[]'] ].reduce((r,s)=>{ if (s.checked) r.push(s.value);return r},[])
console.log('options = ', JSON.stringify( options ))
console.log('products = ', JSON.stringify( products ))
myForm.reset() // clear anything for new testing
console.log(' form reseted')
}
<form name="my-form">
<div class="checkboxs-wrapper">
<input type="radio" name="rGroup_1" required >
<input type="checkbox" name="option[]" value="option1">
<input type="checkbox" name="option[]" value="option2">
<input type="checkbox" name="option[]" value="option3">
</div>
<div class="checkboxs-wrapper">
<input type="radio" name="rGroup_2" required>
<input type="checkbox" name="product[]" value="product1">
<input type="checkbox" name="product[]" value="product2">
<input type="checkbox" name="product[]" value="product3">
</div>
<button type="submit">submit</button>
</form>
Upvotes: 1
Reputation: 16997
if i understant. so you have to give another id and another name of course, try this:
function bindItemsInput() {
var inputs = $("input[type=checkbox]");
var radios = $("input[type=radio]");
function checkCheckboxes () {
var isAtLeastOneServiceSelected = false;
for(var i = inputs.length-1; i >= 0; --i) {
if (inputs[i].checked) isAtLeastOneCheckboxSelected = true;
}
radios.each( function(){
$(this).checked = $(this).siblings($("input[type=checkbox]:checked")).length > 0;
});
}
for(var i = inputs.length-1; i >= 0; --i) {
inputs[i].addEventListener('change', checkCheckboxes)
}
}
Upvotes: 0