Allow radio fields to be set to decheckable on second check - javascript

I would like to be able to set a class name on the container around various radio groups on a page which would allow those radio groups to be uncheckable / detickable - thus allowing the user to set a radio field back to nothing. The names should be assumed to be dynamic so the code is as reusable as possible. I think it is fair to assume that only one unique input name would occur within each element set with the class.
I am aware this is non-standard.
I am aware that similar questions have been put before.
The complexity of the question is handling multiple groups of radios with dynamically generated names in a simple and consistent way. Generally most solutions I have seen keep track of the current selection either by applying classes to the radio inputs in some other way. Any answers that care to discuss the pros and cons of the various events that are best listened to would also be of value.
Example html:
<ul class="detickable-radio">
<li><input name="x1" type="radio" value="a" id="r_1_1"><label for="r_1_1">First Q First A</label></li>
<li><input name="x1" type="radio" value="b" id="r_1_2"><label for="r_1_2">First Q 2nd A</label></li>
</ul>
<ul>
<li><input name="y1" type="radio" value="c" id="r_2_1"><label for="r_2_1">Second Q First A</label></li>
<li><input name="y1" type="radio" value="d" id="r_2_2"><label for="r_2_2">Second Q 2nd A</label></li>
</ul>
<ul class="detickable-radio">
<li><input name="z1" type="radio" value="e" id="r_3_1"><label for="r_3_1">Third Q First A</label></li>
<li><input name="z1" type="radio" value="f" id="r_3_2"><label for="r_3_2">Third Q 2nd A</label></li>
</ul>
Desired Result: the x1 and z1 radios would be uncheckable and the y1 radio would not be.
Vanilla and jQuery answers are both welcome. Cheers.
Update - I have set it as complete although it does not yet function for keyboard entry. In general I would suggest that an approach of keeping track of the checked values and then checking on each change event would give better coverage. Also I think that it would be neater to change checkboxes to allow a single value to be checked than to change a radio to detickable. Also I can't believe Nevada isn't going to provide any further count updates for another day.

You could do something like this:
var s;
$('.detickable-radio input:radio, .detickable-radio input:radio ~ label').mousedown(function(e) {
var $this = $(this).is(":radio") ? $(this) : $(this).prev();
s = $this.is(":checked")
}).mouseup(function(e) {
var $this = $(this).is(":radio") ? $(this) : $(this).prev();
$this.prop("checked", !s)
}).click(function(e) {
e.preventDefault()
});
var s;
$('.detickable-radio input:radio, .detickable-radio input:radio ~ label').mousedown(function(e) {
var $this = $(this).is(":radio") ? $(this) : $(this).prev();
s = $this.is(":checked")
}).mouseup(function(e) {
var $this = $(this).is(":radio") ? $(this) : $(this).prev();
$this.prop("checked", !s)
}).click(function(e) {
e.preventDefault()
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="detickable-radio">
<li><input name="x1" type="radio" value="a" id="r_1_1"><label for="r_1_1">First Q First A</label></li>
<li><input name="x1" type="radio" value="b" id="r_1_2"><label for="r_1_2">First Q 2nd A</label></li>
</ul>
<ul>
<li><input name="y1" type="radio" value="c" id="r_2_1"><label for="r_2_1">Second Q First A</label></li>
<li><input name="y1" type="radio" value="d" id="r_2_2"><label for="r_2_2">Second Q 2nd A</label></li>
</ul>
<ul class="detickable-radio">
<li><input name="z1" type="radio" value="e" id="r_3_1"><label for="r_3_1">Third Q First A</label></li>
<li><input name="z1" type="radio" value="f" id="r_3_2"><label for="r_3_2">Third Q 2nd A</label></li>
</ul>

Related

Disable button if radio is unchecked. Enable when checked

I can't seem to get my button to re-enable after it's been disabled. Currently, if nothing is checked and I mouseover it, the button disables. It stays enabled if I have something checked, but if I first hover over then button, with nothing checked, I can't get it to re-enable if I check something.
Here's My JS:
var inputs = document.getElementsByTagName('input');
var letsCookButton = document.querySelector('#letsCook');
letsCookButton.addEventListener('mouseover', checkIfChecked);
function checkIfChecked() {
letsCookButton.disabled = true;
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].checked) {
letsCookButton.disabled = false;
}
}
}
Here's my HTML:
div class="mainBox" id="box-one">
<p id="left-box-title">What are you looking for?<span>*</span></p>
<ul>
<li><input type="radio" name="food" id="side-food"> Side</li>
<li><input type="radio" name="food" id="main-food"> Main Dish</li>
<li><input type="radio" name="food" id="dessert-food"> Dessert</li>
<li><input type="radio" name="food" id="entire-meal"> Entire Meal</li>
</ul>
<button id="letsCook">LET'S COOK!</button>
</div>
You will have to slightly rethink how you want the UX of your app to work, because disabled elements do not produce events.
Since at least one radio button will remain checked after the first click, I would suggest disabling the button from the start and then enabling it on a radio click event.
<div class="mainBox" id="box-one">
<p id="left-box-title">What are you looking for?<span>*</span></p>
<ul id="radio-group">
<li><input type="radio" name="food" id="side-food"> Side</li>
<li><input type="radio" name="food" id="main-food"> Main Dish</li>
<li><input type="radio" name="food" id="dessert-food"> Dessert</li>
<li><input type="radio" name="food" id="entire-meal"> Entire Meal</li>
</ul>
<button id="letsCook" disabled>LET'S COOK!</button>
</div>
var inputGroup = document.querySelector('#radio-group');
var letsCookButton = document.querySelector('#letsCook');
inputGroup.addEventListener('click', function () {
letsCookButton.removeAttribute('disabled')
});
Working example in JS Fiddle: https://jsfiddle.net/Ollie1700/wxn9f63p/4/

reactivate a checkbox in a dynamic list jquery

I'm trying to reactivate a checkbox in a dynamic list and I do not succeed, the list update its contents every x time.
<div class="content">
<ul class="mylist">
<li><input type="checkbox" class="check" checked>0</li>
<li><input type="checkbox" class="check">1</li>
<li><input type="checkbox" class="check">2</li>
<li><input type="checkbox" class="check">3</li>
<li><input type="checkbox" class="check">4</li>
<li><input type="checkbox" class="check">5</li>
<li><input type="checkbox" class="check">6</li>
<li><input type="checkbox" class="check">7</li>
</ul>
</div>
// checkbox
var checkbox;
var list = [2,3,4,5,6,7,8,9];
//
setInterval(function(){
$('.mylist li').remove();
for(i in list) {
$('.mylist').append('<li><input type="checkbox" class="check">' + i + '</li>');
}
if(typeof checkbox === 'object')
checkbox.prop('checked', true);
}, 3000);
$('.check').on('click', function(){
if ($(this).is(":checked")) {
checkbox = $(this);
}
});
https://jsfiddle.net/ywkr5ezp/3/
The reason this is happening is because the input element stored in checkbox is not the same as the new input element that you are creating. When you store an element in a variable it is storing that specific instance of the element.
One way around this would be to give the checkbox elements id's that you could then reference and recheck.

Tick checkbox via javascript console by lable names

I would like to check boxes via javascript.
The thing is I have a task to check more then 300 checkboxes whith specific names.
I can check one box, or check all boxes... but how to check specific boxes?
Here is an example:
<li id="s1" class="city-select">
<input name="rid" id="r1" value="1" type="checkbox">
<label for="r1" id="l1">Paris</label>
</li>
<li id="s1" class="city-select">
<input name="rid" id="r2" value="2" type="checkbox">
<label for="r2" id="l2">Plovdiv</label>
</li>
<li id="s1" class="city-select">
<input name="rid" id="r3" value="3" type="checkbox">
<label for="r3" id="l3">Berlin</label>
</li>
I would like to tick only "Berlin" and "Paris" - here is what I'm using to tick all:
[].forEach.call(document.querySelectorAll('input[type="checkbox"]'),function(el){el.checked=true});
And here is what am I trying to type:
$("lable:contains('paris, berlin')").prev().find('input').addAttr("checked");
You have wrong selector to target checkboxes. You need to use:
$("label:contains(Paris),label:contains(Berlin)").prev().prop("checked",true);
Working Demo
Update:
var cities = ["Paris","Berlin"];
$("label:contains('" + cities.join("'),label:contains('") + "')").prev().prop("checked",true);
Working Fiddle for update
It looks like your use of prev should be parent or closest.
So you take the current label, go up to the container, then down to the checkbox.
If you use prev then you restrict how much you can change the html (eg if you add a div wrapper around the label in the future, you'll have to change all your code).
given:
<li id="s1" class="city-select">
<input name="rid" id="r3" value="3" type="checkbox">
<label for="r3" id="l3">Berlin</label>
</li>
then use
$("label:contains(Paris),label:contains(Berlin)")
.closest("li")
.find(":checkbox")
.prop("checked",true);
More info at the API documentation: https://api.jquery.com/closest/
How to use this for 300 cities?
This depends on how they are stored. If it's a comma separated list (Paris,Berlin) then split into an array first, if it's json, then convert to an array first...(see the pattern?)
var citiesList = "Paris,Berlin".split(",");
$(citiesList).each(function() {
$("label:contains(" + this + ")")
.closest("li")
.find(":checkbox")
.prop("checked",true);
});

How to show different links when certain questions are answered

How do I make it so that when I click AT&T, 8GB, and Black it shows a link and when I click Other, 8GB, and White it shows a different link. This is what I came up with. This is my first ever attempt so don't be rough on me. I'm trying to achieve something similar to http://glyde.com/sell/iphone-4s.
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
<!--
.bgclr {background-color: white; color: black; font-weight: bold;}
-->
</style>
<script language="JavaScript">
<!-- Begin
var numQues = 3;
var numChoi = 3;
var answers = new Array(3);
// Do not change anything below here ...
function getScore(form) {
var score = 0;
var currElt;
var currSelection;
for (i=0; i<numQues; i++) {
currElt = i*numChoi;
for (j=0; j<numChoi; j++) {
currSelection = form.elements[currElt + j];
if (currSelection.checked) {
if (currSelection.value == answers[i]) {
score++;
break;
}
}
}
}
</script>
</head>
<body>
<form name="quiz">
What carrier do you have?
<ul style="margin-top: 1pt">
<li><input type="radio" name="q1" value="AT&T"/>AT&T</li>
<li><input type="radio" name="q1" value="Other"/>Other</li>
<li><input type="radio" name="q1" value="Unlocked"/>Unlocked</li>
</ul>
What is your phones capicity?
<ul style="margin-top: 1pt">
<li><input type="radio" name="q2" value="8GB"/>8GB</li>
<li><input type="radio" name="q2" value="16GB"/>16GB</li>
</ul>
What color is your phone?
<ul style="margin-top: 1pt">
<li><input type="radio" name="q3" value="Black"/>Black</li>
<li><input type="radio" name="q3" value="White"/>White</li>
</ul>
<input type="button" value="Get score" onClick="getScore(this.form)"/>
</body>
</html>
http://jsfiddle.net/XwN2L/2547/
OK. Add an "onclick" event to each element of the form, which calls a method called tryToMakeLink(). So for every element
<input type="radio" name="q1" value="AT&T"/>
should now read
<input type="radio" onclick=tryToMakeLink(); name="q1" value="AT&T"/>
Also, add a div to the bottom to display the dynamic link.
<form name="quiz" id='quiz'>
What carrier do you have?
<ul style="margin-top: 1pt">
<li><input type="radio" onclick=tryToMakeLink(); name="q1" value="AT&T"/>AT&T</li>
<li><input type="radio" onclick=tryToMakeLink(); name="q1" value="Other"/>Other</li>
<li><input type="radio" onclick=tryToMakeLink(); name="q1" value="Unlocked"/>Unlocked</li>
</ul>
What is your phones capicity?
<ul style="margin-top: 1pt">
<li><input type="radio" onclick=tryToMakeLink(); name="q2" value="8GB"/>8GB</li>
<li><input type="radio" onclick=tryToMakeLink(); name="q2" value="16GB"/>16GB</li>
</ul>
What color is your phone?
<ul style="margin-top: 1pt">
<li><input type="radio" onclick=tryToMakeLink(); name="q3" value="Black"/>Black</li>
<li><input type="radio" onclick=tryToMakeLink(); name="q3" value="White"/>White</li>
</ul>
<input type="button" value="Get score" onClick="getScore(this.form)"/>
<br>
<div id=linkDiv>
--
</div>
</form>
The tryToMakeLink() method does the following:
Look at each radio. If the user has not made a choice for each question, do nothing.
If the user has made a choice for each question, then show 1 link if they have 8gb at&t black, show another link if they have other 8gb white, show a 3rd link if they have any other combination. you can easily add other configurations by adding more else if clauses to the function.
So here it is (JavaScript)
function tryToMakeLink()
{
//get all selected radios
var q1=document.querySelector('input[name="q1"]:checked');
var q2=document.querySelector('input[name="q2"]:checked');
var q3=document.querySelector('input[name="q3"]:checked');
//make sure the user has selected all 3
if (q1==null || q2==null ||q3==null)
{
document.getElementById("linkDiv").innerHTML="--";
}
else
{
//now we know we have 3 radios, so get their values
q1=q1.value;
q2=q2.value;
q3=q3.value;
//now check the values to display a different link for the desired configuration
if (q1=="AT&T" && q2=="8GB" && q3=="Black")
{
document.getElementById("linkDiv").innerHTML="<a href=#>att 8gb black</a>";
}
else if (q1=="Other" && q2=="8GB" && q3=="White")
{
document.getElementById("linkDiv").innerHTML="<a href=#>other 8b white</a>";
}
else
{
document.getElementById("linkDiv").innerHTML="<a href=#>some third option</a>";
}
}
}
This is all javascript, as indicated by your post; however you may want to look into jQuery.
EDIT:
A better way to do this is to bind the click event to each radio when the document loads, instead of needing an "onclick=" in each input tag.
so you add an onload to your body
<body onLoad="attachClickEvents();">
and add this javascript
function attachClickEvents()
{
var inputs=document.getElementById('quiz').elements;
for (var i=0;i<inputs.length;i++)
{
inputs[i].onclick = function() {
tryToMakeLink();
};
}
}
I think that this could help you!
How to change the images on button click
It is another SO question that I found useful for the same thing!

finding value of closest hidden field, located above user click in javascript

I'm trying to grab the value of a hidden field that resides above each group of LI's with javascript, I cannot use jQuery because of an unreasonable client's concerns (believe me, I've tried, they just don't want to "risk" adding a library)... anyway...
The list would look something like this:
<input id="hidden1" type="hidden" value="5" class="includeds">
<h3>header</h3>
<ul class="groups">
<li><input id="li1" type="checkbox" value="1" onclick="value()"></li>
<li><input id="li2" type="checkbox" value="2" onclick="value()"></li>
<li><input id="li3" type="checkbox" value="3" onclick="value()"></li>
</ul>
<input id="hidden2" type="hidden" value="3" class="includeds">
<h3>header2</h3>
<ul class="groups">
<li><input id="li4" type="checkbox" value="4" onclick="value()"></li>
<li><input id="li5" type="checkbox" value="5" onclick="value()"></li>
<li><input id="li6" type="checkbox" value="6" onclick="value()"></li>
</ul>
So if I click on checkbox li1, I want to retrieve the value "5" from the hidden field above it.
If I click li5, I want to get the value of "2" from the first hidden field above it, etc, etc.
in a previous SO question some amazing people helped me do this with jQuery:
if($(this).closest('ul').prevAll('.includeds:first').val() !== '0') {
// logic here
}
but when presented to the client, I ran into the aforementioned complaints. So now I need to do the same thing with javascript vanilla. I appreciate any help or pointers you guys could provide. I apologize for asking the same question twice, between jquery and javascript.
Uhm, the jQuery code I'd use would be:
$(this).parent().prev().prev().val()
With that in mind, all you have to do is rewrite the code to correct plain javascript entities.
The result would be something like:
function getParent(node){
return node.parentNode;
}
function getPrev(node){
do { // loop to find the previous node that is an element
node = node.previousSibling;
}while(node && node.nodeType != 1);
return node;
}
getPrev(getPrev(getParent(this))));
If you can't use jQuery then complex queries like the on you mentioned become much more difficult. In liue of jQuery it's easiest to reference elements by their ID tag or by a class filter (depending on the scenario).
Here i would say the best bet is to hard code the given input ID into the onclick function.
HTML
<input id="hidden2" type="hidden" value="3" class="includeds">
<h3>header2</h3>
<ul class="groups">
<li><input id="li4" type="checkbox" value="4" onclick="value('hidden2')"></li>
<li><input id="li5" type="checkbox" value="5" onclick="value('hidden2')"></li>
<li><input id="li6" type="checkbox" value="6" onclick="value('hidden2')"></li>
</ul>
JavaScript
function value(id) {
var elem = document.getElementByID(id);
...
}

Categories

Resources