my goal is for radio buttons to change an <option> of a <select> element (drop-down list).
I was already able to solve the reverse behavior (selecting another <option> results in a change in a radio button). As you can see here:
function validate()
{
var x = document.getElementById("location_select");
var y = x.options[x.selectedIndex].value;
{
document.getElementById(y).checked = true;
}
}
<select id="location_select" onchange="validate()">
<option value="berlin">Berlin</option>
<option value="paris">Paris</option>
</select>
<label>
<input type="radio" id="berlin" name="location">
<span>Berlin</span>
</label>
<label>
<input type="radio" id="paris" name="location">
<span>Paris</span>
</label>
Now I would like to generate the reverse behavior.
Desired Behavior: Changing the radio button also changes the <option> in my selection.
The radio button ID is the same as the "value" of my drop-down options. So a JS variable can then be used for the ID as well as the "value".
Basically, this is my progress currently:
function validate_2()
{
{
document.getElementById("location_select").selectedIndex = "1";
}
}
<label>
<input type="radio" id="berlin" name="location" onchange="validate_2()">
<span class="title">Berlin</span>
</label>
<label>
<input type="radio" id="paris" name="location" onchange="validate_2()">
<span class="title">Paris</span>
</label>
<select id="location_select">
<option value="berlin">Berlin</option>
<option value="paris">Paris</option>
</select>
As you can see, it's only static so far.
I'm open to better methods if this isn't a good one.
This function can change selected option of <select> by changing radio inputs
Get the id of the radio input which was changed and set value attribute of <select> tag
Version 1
function validate_2() {
checkedVal = event.target.id;
locationSelect = document.getElementById("location_select");
locationSelect.value = checkedVal;
}
Version 2
It can be shortened to
function validate_2() {
// ID becomes variable in JS
location_select.value = event.target.id;
}
Version 3
Using selectedIndex explicitly
function validate_2() {
checkedVal = event.target.id;
locationSelect = document.getElementById("location_select");
indexToSelect = Array.from(locationSelect.options).findIndex(opt => opt.value == checkedVal);
locationSelect.selectedIndex = indexToSelect;
}
function validate_2(city)
{
document.getElementById("location_select").value = city;
}
function validate_1(){
radio = document.getElementsByTagName('input')
if(radio[0].checked)radio[1].checked = true
else if (radio[1].checked)radio[0].checked = true
}
<label>
<input type="radio" id="berlin" name="location" onchange="validate_2('berlin')" checked>
<span class="title">Berlin</span>
</label>
<label>
<input type="radio" id="paris" name="location" onchange="validate_2('paris')">
<span class="title">Paris</span>
</label>
<select id="location_select" onChange="validate_1()">
<option value="berlin">Berlin</option>
<option value="paris">Paris</option>
</select>
When using the newer browsers that support HTML5 (FireFox 4 for example);
and a form field has the attribute required='required';
and the form field is empty/blank;
and the submit button is clicked;
the browsers detects that the "required" field is empty and does not submit the form; instead browser shows a hint asking the user to type text into the field.
Now, instead of a single text field, I have a group of checkboxes, out of which at least one should be checked/selected by the user.
How can I use the HTML5 required attribute on this group of checkboxes?
(Since only one of the checkboxes needs to be checked, I can't put the required attribute on each and every checkbox)
ps. I am using simple_form, if that matters.
UPDATE
Could the HTML 5 multiple attribute be helpful here? Has anyone use it before for doing something similar to my question?
UPDATE
It appears that this feature is not supported by the HTML5 spec: ISSUE-111: What does input.#required mean for #type = checkbox?
(Issue status: Issue has been marked closed without prejudice.)
And here is the explanation.
UPDATE 2
It's an old question, but wanted to clarify that the original intent of the question was to be able to do the above without using Javascript - i.e. using a HTML5 way of doing it. In retrospect, I should've made the "without Javascript" more obvious.
Unfortunately HTML5 does not provide an out-of-the-box way to do that.
However, using jQuery, you can easily control if a checkbox group has at least one checked element.
Consider the following DOM snippet:
<div class="checkbox-group required">
<input type="checkbox" name="checkbox_name[]">
<input type="checkbox" name="checkbox_name[]">
<input type="checkbox" name="checkbox_name[]">
<input type="checkbox" name="checkbox_name[]">
</div>
You can use this expression:
$('div.checkbox-group.required :checkbox:checked').length > 0
which returns true if at least one element is checked.
Based on that, you can implement your validation check.
Its a simple trick. This is jQuery code that can exploit the html5 validation by changing the required properties if any one is checked. Following is your html code (make sure that you add required for all the elements in the group.)
<input type="checkbox" name="option[]" id="option-1" value="option1" required/> Option 1
<input type="checkbox" name="option[]" id="option-2" value="option2" required/> Option 2
<input type="checkbox" name="option[]" id="option-3" value="option3" required/> Option 3
<input type="checkbox" name="option[]" id="option-4" value="option4" required/> Option 4
<input type="checkbox" name="option[]" id="option-5" value="option5" required/> Option 5
Following is jQuery script, which disables further validation check if any one is selected. Select using name element.
$cbx_group = $("input:checkbox[name='option[]']");
$cbx_group = $("input:checkbox[id^='option-']"); // name is not always helpful ;)
$cbx_group.prop('required', true);
if($cbx_group.is(":checked")){
$cbx_group.prop('required', false);
}
Small gotcha here: Since you are using html5 validation, make sure you execute this before the it gets validated i.e. before form submit.
// but this might not work as expected
$('form').submit(function(){
// code goes here
});
// So, better USE THIS INSTEAD:
$('button[type="submit"]').on('click', function() {
// skipping validation part mentioned above
});
HTML5 does not directly support requiring only one/at least one checkbox be checked in a checkbox group. Here is my solution using Javascript:
HTML
<input class='acb' type='checkbox' name='acheckbox[]' value='1' onclick='deRequire("acb")' required> One
<input class='acb' type='checkbox' name='acheckbox[]' value='2' onclick='deRequire("acb")' required> Two
JAVASCRIPT
function deRequireCb(elClass) {
el = document.getElementsByClassName(elClass);
var atLeastOneChecked = false; //at least one cb is checked
for (i = 0; i < el.length; i++) {
if (el[i].checked === true) {
atLeastOneChecked = true;
}
}
if (atLeastOneChecked === true) {
for (i = 0; i < el.length; i++) {
el[i].required = false;
}
} else {
for (i = 0; i < el.length; i++) {
el[i].required = true;
}
}
}
The javascript will ensure at least one checkbox is checked, then de-require the entire checkbox group. If the one checkbox that is checked becomes un-checked, then it will require all checkboxes, again!
I guess there's no standard HTML5 way to do this, but if you don't mind using a jQuery library, I've been able to achieve a "checkbox group" validation using webshims' "group-required" validation feature:
The docs for group-required say:
If a checkbox has the class 'group-required' at least one of the
checkboxes with the same name inside the form/document has to be
checked.
And here's an example of how you would use it:
<input name="checkbox-group" type="checkbox" class="group-required" id="checkbox-group-id" />
<input name="checkbox-group" type="checkbox" />
<input name="checkbox-group" type="checkbox" />
<input name="checkbox-group" type="checkbox" />
<input name="checkbox-group" type="checkbox" />
I mostly use webshims to polyfill HTML5 features, but it also has some great optional extensions like this one.
It even allows you to write your own custom validity rules. For example, I needed to create a checkbox group that wasn't based on the input's name, so I wrote my own validity rule for that...
we can do this easily with html5 also, just need to add some jquery code
Demo
HTML
<form>
<div class="form-group options">
<input type="checkbox" name="type[]" value="A" required /> A
<input type="checkbox" name="type[]" value="B" required /> B
<input type="checkbox" name="type[]" value="C" required /> C
<input type="submit">
</div>
</form>
Jquery
$(function(){
var requiredCheckboxes = $('.options :checkbox[required]');
requiredCheckboxes.change(function(){
if(requiredCheckboxes.is(':checked')) {
requiredCheckboxes.removeAttr('required');
} else {
requiredCheckboxes.attr('required', 'required');
}
});
});
Inspired by the answers from #thegauraw and #Brian Woodward, here's a bit I pulled together for JQuery users, including a custom validation error message:
$cbx_group = $("input:checkbox[name^='group']");
$cbx_group.on("click", function () {
if ($cbx_group.is(":checked")) {
// checkboxes become unrequired as long as one is checked
$cbx_group.prop("required", false).each(function () {
this.setCustomValidity("");
});
} else {
// require checkboxes and set custom validation error message
$cbx_group.prop("required", true).each(function () {
this.setCustomValidity("Please select at least one checkbox.");
});
}
});
Note that my form has some checkboxes checked by default.
Maybe some of you JavaScript/JQuery wizards could tighten that up even more?
I added an invisible radio to a group of checkboxes.
When at least one option is checked, the radio is also set to check.
When all options are canceled, the radio is also set to cancel.
Therefore, the form uses the radio prompt "Please check at least one option"
You can't use display: none because radio can't be focused.
I make the radio size equal to the entire checkboxes size, so it's more obvious when prompted.
HTML
<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>
Javascript
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)
}
CSS
.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;
}
https://jsfiddle.net/codus/q6ngpjyc/9/
I had the same problem and I my solution was this:
HTML:
<form id="processForm.php" action="post">
<div class="input check_boxes required wish_payment_type">
<div class="wish_payment_type">
<span class="checkbox payment-radio">
<label for="wish_payment_type_1">
<input class="check_boxes required" id="wish_payment_type_1" name="wish[payment_type][]" type="checkbox" value="1">Foo
</label>
</span>
<span class="checkbox payment-radio">
<label for="wish_payment_type_2">
<input class="check_boxes required" id="wish_payment_type_2" name="wish[payment_type][]" type="checkbox" value="2">Bar
</label>
</span>
<span class="checkbox payment-radio">
<label for="wish_payment_type_3">
<input class="check_boxes required" id="wish_payment_type_3" name="wish[payment_type][]" type="checkbox" value="3">Buzz
</label>
<input id='submit' type="submit" value="Submit">
</div>
</form>
JS:
var verifyPaymentType = function () {
var checkboxes = $('.wish_payment_type .checkbox');
var inputs = checkboxes.find('input');
var first = inputs.first()[0];
inputs.on('change', function () {
this.setCustomValidity('');
});
first.setCustomValidity(checkboxes.find('input:checked').length === 0 ? 'Choose one' : '');
}
$('#submit').click(verifyPaymentType);
https://jsfiddle.net/oywLo5z4/
You don't need jQuery for this. Here's a vanilla JS proof of concept using an event listener on a parent container (checkbox-group-required) of the checkboxes, the checkbox element's .checked property and Array#some.
const validate = el => {
const checkboxes = el.querySelectorAll('input[type="checkbox"]');
return [...checkboxes].some(e => e.checked);
};
const formEl = document.querySelector("form");
const statusEl = formEl.querySelector(".status-message");
const checkboxGroupEl = formEl.querySelector(".checkbox-group-required");
checkboxGroupEl.addEventListener("click", e => {
statusEl.textContent = validate(checkboxGroupEl) ? "valid" : "invalid";
});
formEl.addEventListener("submit", e => {
e.preventDefault();
if (validate(checkboxGroupEl)) {
statusEl.textContent = "Form submitted!";
// Send data from e.target to your backend
}
else {
statusEl.textContent = "Error: select at least one checkbox";
}
});
<form>
<div class="checkbox-group-required">
<input type="checkbox">
<input type="checkbox">
<input type="checkbox">
<input type="checkbox">
</div>
<input type="submit" />
<div class="status-message"></div>
</form>
If you have multiple groups to validate, add a loop over each group, optionally adding error messages or CSS to indicate which group fails validation:
const validate = el => {
const checkboxes = el.querySelectorAll('input[type="checkbox"]');
return [...checkboxes].some(e => e.checked);
};
const allValid = els => [...els].every(validate);
const formEl = document.querySelector("form");
const statusEl = formEl.querySelector(".status-message");
const checkboxGroupEls = formEl.querySelectorAll(".checkbox-group-required");
checkboxGroupEls.forEach(el =>
el.addEventListener("click", e => {
statusEl.textContent = allValid(checkboxGroupEls) ? "valid" : "invalid";
})
);
formEl.addEventListener("submit", e => {
e.preventDefault();
if (allValid(checkboxGroupEls)) {
statusEl.textContent = "Form submitted!";
}
else {
statusEl.textContent = "Error: select at least one checkbox from each group";
}
});
<form>
<div class="checkbox-group-required">
<label>
Group 1:
<input type="checkbox">
<input type="checkbox">
<input type="checkbox">
<input type="checkbox">
</label>
</div>
<div class="checkbox-group-required">
<label>
Group 2:
<input type="checkbox">
<input type="checkbox">
<input type="checkbox">
<input type="checkbox">
</label>
</div>
<input type="submit" />
<div class="status-message"></div>
</form>
I realize there are a ton of solutions here, but I found none of them hit every requirement I had:
No custom coding required
Code works on page load
No custom classes required (checkboxes or their parent)
I needed several checkbox lists to share the same name for submitting Github issues via their API, and was using the name label[] to assign labels across many form fields (two checkbox lists and a few selects and textboxes) - granted I could have achieved this without them sharing the same name, but I decided to try it, and it worked.
The only requirement for this one is jQuery, which could easily be eliminated if you wanted to rewrite it in vanilla JS. You can combine this with #ewall's great solution to add custom validation error messages.
/* required checkboxes */
jQuery(function ($) {
var $requiredCheckboxes = $("input[type='checkbox'][required]");
/* init all checkbox lists */
$requiredCheckboxes.each(function (i, el) {
//this could easily be changed to suit different parent containers
var $checkboxList = $(this).closest("div, span, p, ul, td");
if (!$checkboxList.hasClass("requiredCheckboxList"))
$checkboxList.addClass("requiredCheckboxList");
});
var $requiredCheckboxLists = $(".requiredCheckboxList");
$requiredCheckboxLists.each(function (i, el) {
var $checkboxList = $(this);
$checkboxList.on("change", "input[type='checkbox']", function (e) {
updateCheckboxesRequired($(this).parents(".requiredCheckboxList"));
});
updateCheckboxesRequired($checkboxList);
});
function updateCheckboxesRequired($checkboxList) {
var $chk = $checkboxList.find("input[type='checkbox']").eq(0),
cblName = $chk.attr("name"),
cblNameAttr = "[name='" + cblName + "']",
$checkboxes = $checkboxList.find("input[type='checkbox']" + cblNameAttr);
if ($checkboxList.find(cblNameAttr + ":checked").length > 0) {
$checkboxes.prop("required", false);
} else {
$checkboxes.prop("required", true);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form method="post" action="post.php">
<div>
Type of report:
</div>
<div>
<input type="checkbox" id="chkTypeOfReportError" name="label[]" value="Error" required>
<label for="chkTypeOfReportError">Error</label>
<input type="checkbox" id="chkTypeOfReportQuestion" name="label[]" value="Question" required>
<label for="chkTypeOfReportQuestion">Question</label>
<input type="checkbox" id="chkTypeOfReportFeatureRequest" name="label[]" value="Feature Request" required>
<label for="chkTypeOfReportFeatureRequest">Feature Request</label>
</div>
<div>
Priority
</div>
<div>
<input type="checkbox" id="chkTypeOfContributionBlog" name="label[]" value="Priority: High" required>
<label for="chkPriorityHigh">High</label>
<input type="checkbox" id="chkTypeOfContributionBlog" name="label[]" value="Priority: Medium" required>
<label for="chkPriorityMedium">Medium</label>
<input type="checkbox" id="chkTypeOfContributionLow" name="label[]" value="Priority: Low" required>
<label for="chkPriorityMedium">Low</label>
</div>
<div>
<input type="submit" />
</div>
</form>
Really simple way to verify if at least one checkbox is checked:
function isAtLeastOneChecked(name) {
let checkboxes = Array.from(document.getElementsByName(name));
return checkboxes.some(e => e.checked);
}
Then you can implement whatever logic you want to display an error.
Here is another simple trick using Jquery!!
HTML
<form id="hobbieform">
<div>
<input type="checkbox" name="hobbies[]">Coding
<input type="checkbox" name="hobbies[]">Gaming
<input type="checkbox" name="hobbies[]">Driving
</div>
</form>
JQuery
$('#hobbieform').on("submit", function (e) {
var arr = $(this).serialize().toString();
if(arr.indexOf("hobbies") < 0){
e.preventDefault();
alert("You must select at least one hobbie");
}
});
That's all.. this works because if none of the checkbox is selected, nothing as regards the checkbox group(including its name) is posted to the server
Pure JS solution:
const group = document.querySelectorAll('[name="myCheckboxGroup"]');
function requireLeastOneChecked() {
var atLeastOneChecked = false;
for (i = 0; i < group.length; i++)
if (group[i].checked)
atLeastOneChecked = true;
if (atLeastOneChecked)
for (i = 0; i < group.length; i++)
group[i].required = false;
else
for (i = 0; i < group.length; i++)
group[i].required = true;
}
requireLeastOneChecked(); // onload
group.forEach(function ($el) {
$el.addEventListener('click', function () { requireLeastOneChecked(); })
});
Hi just use a text box additional to group of check box.When clicking on any check box put values in to that text box.Make that that text box required and readonly.
A general Solution without change the submit event or knowing the name of the checkboxes
Build a Function, which marks the Checkbox as HTML5-Invalid
Extend Change-Event and check validity on the start
jQuery.fn.getSiblingsCheckboxes = function () {
let $this = $(this);
let $parent = $this.closest('form, .your-checkbox-listwrapper');
return $parent.find('input[type="checkbox"][name="' + $this.attr('name')+'"]').filter('*[required], *[data-required]');
}
jQuery.fn.checkRequiredInputs = function() {
return this.each(function() {
let $this = $(this);
let $parent = $this.closest('form, .your-checkbox-list-wrapper');
let $allInputs = $this.getSiblingsCheckboxes();
if ($allInputs.filter(':checked').length > 0) {
$allInputs.each(function() {
// this.setCustomValidity(''); // not needed
$(this).removeAttr('required');
$(this).closest('li').css('color', 'green'); // for debugging only
});
} else {
$allInputs.each(function() {
// this.reportValidity(); // not needed
$(this).attr('required', 'required');
$(this).closest('li').css('color', 'red'); // for debugging only
});
}
return true;
});
};
$(document).ready(function() {
$('input[type="checkbox"][required="required"], input[type="checkbox"][required]').not('*[data-required]').not('*[disabled]').each(function() {
let $input = $(this);
let $allInputs = $input.getSiblingsCheckboxes();
$input.attr('data-required', 'required');
$input.removeAttr('required');
$input.on('change', function(event) {
$input.checkRequiredInputs();
});
});
$('input[type="checkbox"][data-required="required"]').checkRequiredInputs();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
</head>
<form>
<ul>
<li><input type="checkbox" id="checkbox1" name="countries" value="Argentina" required="required">Argentina</li>
<li><input type="checkbox" id="checkbox2" name="countries" value="France" required="required">France</li>
<li><input type="checkbox" id="checkbox3" name="countries" value="Germany" required="required">Germany</li>
<li><input type="checkbox" id="checkbox4" name="countries" value="Japan" required="required">Japan</li>
<li><input type="checkbox" id="checkbox5" name="countries" value="Australia" required="required">Australia</li>
</ul>
<input type="submit" value="Submit">
</form>
Try:
self.request.get('sports_played', allow_multiple=True)
or
self.request.POST.getall('sports_played')
More specifically:
When you are reading data from the checkbox array, make sure array has:
len>0
In this case:
len(self.request.get('array', allow_multiple=True)) > 0
I need a solution
I have two radio buttons for measurement in cm and inch.
<html>
<lable class="radioinline">Measurement(cm)</lable>
<input type="radio" name="size" id="radio0"></input>
<lable class="radioinline">Measurement(inch)</lable>
<input type="radio" name="size" id="radio1"></input>
</html>
and one dropdown list box with below listed values in hidden form.
<select id="measure" name="chest" hidden>
<option>70cm/27Inch</option>
<option>71cm/28Inch</option>
<option>72cm/29Inch</option>
</select>
my requirement is on click of radio button either I get the values in cm or in inch in dropdown list which is actually in format of "cm/inch".
Please help to resolve it.
Change the select option while clicking radio button.
Try this code.
$(document).ready(function() {
$("#radio0").click(function() {
var measure = $("#measure");
measure.show();
measure.find("option").remove();
measure.append("<option>70cm</option>");
measure.append("<option>71cm</option>");
measure.append("<option>72cm</option>");
});
$("#radio1").click(function() {
var measure = $("#measure");
measure.show();
measure.find("option").remove();
measure.append("<option>27Inch</option>");
measure.append("<option>28Inch</option>");
measure.append("<option>29Inch</option>");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label class="radioinline">Measurement(cm)</label>
<input type="radio" name="size" id="radio0" />
<label class="radioinline">Measurement(inch)</label>
<input type="radio" name="size" id="radio1" />
<select id="measure" name="chest" hidden>
<option>70cm/27Inch</option>
<option>71cm/28Inch</option>
<option>72cm/29Inch</option>
</select>
Hope this will help you.
Modified Answer
Store the value in data property for each option and use that value while clicking the radio buttons
Try this code.
$(document).ready(function() {
$("#radio0").click(function() {
var measure = $("#measure"),
options = measure.find("option");
options.each(function() {
var value = $(this).data("value").split("/")[0];
$(this).text(value);
});
measure.show();
});
$("#radio1").click(function() {
var measure = $("#measure"),
options = measure.find("option");
options.each(function() {
var value = $(this).data("value").split("/")[1];
$(this).text(value);
});
measure.show();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label class="radioinline">Measurement(cm)</label>
<input type="radio" name="size" id="radio0" />
<label class="radioinline">Measurement(inch)</label>
<input type="radio" name="size" id="radio1" />
<select id="measure" name="chest" hidden>
<option data-value="70cm/27Inch">70cm/27Inch</option>
<option data-value="71cm/28Inch">71cm/28Inch</option>
<option data-value="72cm/29Inch">72cm/29Inch</option>
</select>
I cannot find a perfect solution for this.
Is there a simple way to fadeIn the ".filter_on" div, if I click on a select option and/or radio button?
And by default, get this div to fade out again afterwards?
My fiddle
<div class="filter">
Filter <span class="filter_on">active</span>
</div>
<form>
<p>Vehicle?</p>
<select name="vehicle" size="2">
<option>Bike</option>
<option>Car</option>
</select>
</form>
<form>
<p>City?</p>
<input type="radio" id="all" name="city" value="All" checked>
<label for="all"> All</label></input>
<input type="radio" id="ny" name="city" value="New York">
<label for="ny"> New York</label></input>
<input type="radio" id="mh" name="city" value="Manhattan">
<label for="mh"> Manhattan</label></input>
</form>
You don't need to fadeOut since you cannot unselect from drop-down or cannot uncheck the radio button.
$('select, :radio').on('change', function() {
if ($('select option:selected').length === 0 && $(':radio:checked').val() === 'All') {
$('.filter_on').fadeOut();
} else {
$('.filter_on').fadeIn();
}
}).trigger('change');
trigger will execute this function automatically. Will fadeIn on the page load.
Demo: https://jsfiddle.net/tusharj/vyd7a2s8/1/
Demo -> http://jsfiddle.net/vyd7a2s8/4/
var defaultRadio = $(':radio:checked');
var defaultVehicle = $('[name=vehicle] option:selected');
$('[name=vehicle],[name=city]').on('change', function (e) {
var currentRadio = $(':radio:checked');
var currentVehicle = $('[name=vehicle] option:selected');
if (currentRadio[0].isEqualNode(defaultRadio[0]) && currentVehicle[0].isEqualNode(defaultVehicle[0])) {
$('.filter_on').fadeOut(500);
} else {
$('.filter_on').fadeIn(500);
}
});
Explanation - This will store the default selected values outside the function and uses them inside the click event to check the newly selected values.
I have a web application I'm working on that requires a HTML multiple select element operates like the control key is held down at all times. I.e. click on an option will toggle whether it is selected or not.
I have tried various Jquery event binds but it appears that the standard HTML multiple select behavior executes before the Jquery bound event fires, making it all but impossible to simply intercept the event and modify the standard behavior.
How can I make is so that single clicks will toggle the selection of an individual option?
Try this out. You can store the option values in an object and use the click action to update the object then apply the changes to the select.
Demo
http://jsfiddle.net/iambriansreed/BSdxE/
HTML
<select class="select-toggle" multiple="multiple">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
JavaScript
$('.select-toggle').each(function(){
var select = $(this), values = {};
$('option',select).each(function(i, option){
values[option.value] = option.selected;
}).click(function(event){
values[this.value] = !values[this.value];
$('option',select).each(function(i, option){
option.selected = values[option.value];
});
});
});
You may want to consider a simpler solution, like using a list of checkboxes inside a div whose overflow property is set to scroll. That might work out better for you. Getting a drop down to do what you've asked is a bit involved.
See this for example:
label{display:block;}
#container{height:100px;width:200px;overflow:scroll;}
<div id="container">
<label><input type="checkbox" name="test" value="1" />Option 1</label>
<label><input type="checkbox" name="test" value="2" />Option 2</label>
<label><input type="checkbox" name="test" value="3" />Option 3</label>
<label><input type="checkbox" name="test" value="4" />Option 4</label>
<label><input type="checkbox" name="test" value="5" />Option 5</label>
<label><input type="checkbox" name="test" value="6" />Option 6</label>
<label><input type="checkbox" name="test" value="7" />Option 7</label>
<label><input type="checkbox" name="test" value="8" />Option 8</label>
<label><input type="checkbox" name="test" value="9" />Option 9</label>
<label><input type="checkbox" name="test" value="10" />Option 10</label>
<label><input type="checkbox" name="test" value="11" />Option 11</label>
<label><input type="checkbox" name="test" value="12" />Option 12</label>
</div>
Had to solve this problem myself and noticed the bugged behavior a simple interception of the mousedown and setting the attribute would have, so made a override of the select element and it works good.
jsFiddle: http://jsfiddle.net/51p7ocLw/
Note: This code does fix buggy behavior by replacing the select element in the DOM. This is a bit agressive and will break event handlers you might have attached to the element.
window.onmousedown = function (e) {
var el = e.target;
if (el.tagName.toLowerCase() == 'option' && el.parentNode.hasAttribute('multiple')) {
e.preventDefault();
// toggle selection
if (el.hasAttribute('selected')) el.removeAttribute('selected');
else el.setAttribute('selected', '');
// hack to correct buggy behavior
var select = el.parentNode.cloneNode(true);
el.parentNode.parentNode.replaceChild(select, el.parentNode);
}
}
<h4>From</h4>
<div>
<select name="sites-list" size="7" multiple>
<option value="site-1">SITE</option>
<option value="site-2" selected>SITE</option>
<option value="site-3">SITE</option>
<option value="site-4">SITE</option>
<option value="site-5">SITE</option>
<option value="site-6" selected>SITE</option>
<option value="site-7">SITE</option>
<option value="site-8">SITE</option>
<option value="site-9">SITE</option>
</select>
</div>
The above solutions all have the major downside of not supporting selections in the checkbox, which is actually the reason I'd use <select>-boxes over checkbox-inputs in the first place. Initially I visited this page to find a built-in way to fix this, but considering the above answers, I'll just write my own code.
The following code also has the advantage that it doesn't update on mouseup as opposed to the current top answer by iambriansreed, but on mousedown, which is the default behaviour in browsers.
Just to help out future googlers, my code below:
// Copyright (c) 2018 Joeytje50. All rights reserved.
// This code is licenced under GNU GPL3+; see <http://www.gnu.org/licenses/>
// Source code and most recent version:
// https://gist.github.com/Joeytje50/2b73f9ac47010e7fdc5589788b80af77
// select all <options> within `sel` in the range [from,to]
// change their state to the state sel.options[from] is in,
// ie. change it to the current state of the first selected element
function selectRange(sel, from, to) {
var toState = sel.options[from].selected;
// make sure from < to:
if (from > to) {
var temp = from;
from = to;
to = temp;
}
if (!(sel instanceof HTMLSelectElement)) {
throw new TypeError('selectRange requires a single non-jQuery select-element as first parameter');
}
// (de)select every element
for (var i=from; i<=to; i++) {
sel.options[i].selected = toState;
}
}
$(function() {
$('.addSelect').data('select-start', 0); // default selection start
$('.addSelect').on('mousedown', function(e) {
$(this).focus();
// clicking on the edge of the <select> shouldn't do anything special
if (!$(e.target).is('option')) return;
// if Ctrl is pressed, just let the built-in functionality take over
if (e.ctrlKey) return;
// keep everything selected that's not affected by the range within a shift-click
if (e.shiftKey) {
var fromIdx = $(this).data('select-start')
selectRange(this, $(this).data('select-start'), e.target.index);
e.preventDefault();
return false;
}
// save the starting <option> and the state to change to
$(this).data('select-start', e.target.index);
e.target.selected = !e.target.selected;
e.preventDefault();
// save a list of selected elements, to make sure only the selected <options>
// are added or removed when dragging
var selected = [];
for (var i=0;i<this.selectedOptions.length;i++) {
selected.push(this.selectedOptions[i].index);
}
$(this).data('selected', selected);
$(this).children('option').on('mouseenter', function(e) {
var sel = this.parentElement;
// first reset all options to the original state
for (var i=0;i<sel.options.length;i++) {
if ($(sel).data('selected').indexOf(i) == -1) {
sel.options[i].selected = false;
} else {
sel.options[i].selected = true;
}
}
// then apply the new range to the elements
selectRange(sel, $(sel).data('select-start'), e.target.index);
});
});
// clean up events after click event has ended.
$(window).on('mouseup', function() {
$('.addSelect').children('option').off('mouseenter'); // remove mouseenter-events
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="addSelect" multiple size="10">
<option value="0">Foo0</option>
<option value="1">Bar1</option>
<option value="2">Baz2</option>
<option value="3">Lol3</option>
<option value="4">Heh4</option>
<option value="5">Hey5</option>
<option value="6">Meh6</option>
<option value="7">Xcq7</option>
<option value="8">Hmm8</option>
<option value="9">End9</option>
</select>
Feel free to use this code by simply copying it to any project you'd like to use it on.