I have a problem with a function that selects active items. There are some input/label fields with sectoins ( one section - one active/clicked element )
It only works when I double-click. If I click one time then no result. I can set setTimeout for that code and then works but not always.
Example:
var radios = document.querySelectorAll('#calculator input[type=radio]');
var label = document.querySelectorAll("#calculator label");
function active(e) {
radios.forEach((el,index) => {
if(el.checked === true) {
console.log('true');
label[index].classList.add('active');
} else {
console.log('false');
label[index].classList.remove('active');
}
})
}
Example html field:
<input id="p75" type="radio" name="geodesic_size" value="11250" >
<label for="p75">
<input id="p30" type="radio" name="geodesic_size" value="5626" checked>
<label for="p30">
Not sure if this is what you need, but here's an example of toggling the active class when the checked input changes:
const radios = document.querySelectorAll('input[type="radio"]');
const label = document.querySelectorAll("label");
function active(e) {
radios.forEach((el,index) => {
if(el.checked === true) {
console.log('true');
label[index].classList.add('active');
} else {
console.log('false');
label[index].classList.remove('active');
}
})
}
radios.forEach(el => {
el.addEventListener('change', active);
})
.active {
color: red;
}
<input id="p75" type="radio" name="geodesic_size" value="11250" >
<label for="p75">First</label>
<input id="p30" type="radio" name="geodesic_size" value="5626" checked>
<label for="p30" class="active">Second</label>
The other answers seem to work fine, I would just add a couple suggestions:
First, you can also access the label(s) associated to an element with HTMLInputElement.labels. Using el.labels[0] would IMO be a bit more robust than relying on the index of the radio button and the label to be the same.
If all you need to do is toggle an active class like this, you could accomplish the same thing with CSS only by using the adjacent sibling combinator (+) and get rid of all the JavaScript:
input:checked + label {
color: red;
}
<div>
<input id="p75" type="radio" name="geodesic_size" value="11250">
<label for="p75">p75</label>
</div>
<div>
<input id="p30" type="radio" name="geodesic_size" value="5626" checked>
<label for="p30">p30</label>
</div>
There was no major change I have just add <div id="calculator"></div>.
As #calculator input[type=radio] this means select all input with type equals to radio, which are children of id #calculator.
Then selected all inputs loop through them attach onclick event and put you logic for active() function there.
To see visual effect added .active{background-color:red;} css.
var radios = document.querySelectorAll('#calculator input[type=radio]');
var label = document.querySelectorAll("#calculator label");
radios.forEach(radioBtn => {
radioBtn.onclick = function() {
radios.forEach((el, index) => {
console.log(el.checked);
if (el.checked === true) {
console.log('true');
label[index].classList.add('active');
} else {
console.log('false');
label[index].classList.remove('active');
}
})
};
})
.active {
background-color: red;
}
<div id="calculator">
<input id="p75" type="radio" name="geodesic_size" value="11250">
<label for="p75">p75</label>
<input id="p30" type="radio" name="geodesic_size" value="5626" checked>
<label for="p30">p30</label>
</div>
Unfortunately I noticed one problem with event 'change' for input fields. When I click on default element ( input default checked ) then there is no change but it is normal because the state has not changed and the event did not call the function active(). Of course we can add window.onload with that function to change the styles of the clicked element. But I modified the script to add an async function toogle() for checked elements and works very well.
function active() {
radios.forEach(el => {
if(el.checked === true) {
toogle(el);
} else {
el.labels[0].classList.remove('active');
el.labels[0].setAttribute('data-before', '');
}
});
}
async function toogle(el) {
var f = await new Promise(resolve => {
el.labels[0].classList.add('active');
el.labels[0].setAttribute('data-before', '\uf058');
resolve('resolved');
})
console.log(f);
}
Related
I am trying to show div if one of the two checkboxes is checked. I found it in some article but with the same name, I am using a different name for each checkbox to store it into mysql. My current javascript code is
document.addEventListener('change', function(jj) {
function jj() {
if ((document.getElementById('jj1_ikk').checked) || (document.getElementById('jj2_ikk').checked)) {
document.getElementById('jsa').style.display="block";
} else {
document.getElementById('jsa').style.display="none";
}
}
})
the input fields are
<input type="checkbox" id="jj1_ikk" name="jj1_ikk" /><label for="jj1_ikk">A</label>
<input type="checkbox" id="jj2_ikk" name="jj2_ikk" /><label for="jj2_ikk">B</label>
where jj1_ikk and jj2_ikk are the checkboxes id, and jsa is the div that I want to do show/hide.
I hope my description is clear, thank you.
You can put two check box in span and check changes onclick span like this
HTML
<span onclick="CheckChanges()">
<input type="checkbox" id="jj1_ikk" name="jj1_ikk" /><label for="jj1_ikk">A</label>
<input type="checkbox" id="jj2_ikk" name="jj2_ikk" /><label for="jj2_ikk">B</label>
</span>
<div id="jsa">This is the element that will be shown if both checkboxes aren't checked</div>
JavaScript
var aCheckBox = document.getElementById("jj1_ikk")
var bCheckBox = document.getElementById("jj2_ikk")
function CheckChanges() {
if (aCheckBox.checked == true || bCheckBox.checked == true) {
document.getElementById("jsa").style.display = "block"
} else {
document.getElementById("jsa").style.display = "none"
}
}
You did a mistake when adding the handler for the change event defining two nested functions. Plus I added the event handler only once the document was loaded. You can test the code in this snippet:
//when the document has been loaded, adds the event handlers to the checkboxes
document.addEventListener("DOMContentLoaded", () => {
document.addEventListener('change', () => addHandlers());
});
/**
* Adds handler for the change event on both checkboxes
*/
function addHandlers(){
let jj1 = document.getElementById('jj1_ikk');
let jj2 = document.getElementById('jj2_ikk');
jj1.addEventListener('change', updateMsgVisibility);
jj2.addEventListener('change', updateMsgVisibility);
}
/**
* Show/Hide #jsa based on checkboxes status
*/
function updateMsgVisibility(){
let jj1 = document.getElementById('jj1_ikk');
let jj2 = document.getElementById('jj2_ikk');
if ( (jj1 && (jj1.checked)) || (jj2 && (jj2.checked)) ) {
document.getElementById('jsa').style.display="block";
} else {
document.getElementById('jsa').style.display="none";
}
}
<input type="checkbox" id="jj1_ikk" name="jj1_ikk" /><label for="jj1_ikk">A</label>
<input type="checkbox" id="jj2_ikk" name="jj2_ikk" /><label for="jj2_ikk">B</label>
<div id="jsa" style="display:none;">This is the element that will be shown if both checkboxes aren't checked</div>
here you can see what I want to implement
Hey I'm stuck at this: I want that the launch button gets enabled after all checkboxes are checked and all ranges are set to max.
But something like this won't work:
while(checkboxes.unchecked && ranges.value !== '100') {
if (checkboxes.checked && ranges.value == '100')
document.getElementById('launch').disabled = false;
}
Any tipps for implementation?
The example below uses the HTMLFormElement interface to reference <form>, <input>, and <button> (<fieldset> and <legend> as well if it was needed), you should notice it's terse syntax compared to the standard HTMLElement interfaces.
Solution
Wrap everthing in a <form> tag if you haven't already. Also assign a [name] shared between all ranges and a different [name] shared between all checkboxes. Reference it, then bind the event handler (ie allFields(e)) to the <form> and listen for the "change" event.
const form = document.forms[0];
form.onchange = allFields;
By default all event handlers pass the Event Object (e, event, evt, etc). Reference the <form> with this keyword coupled with the .elements property. That will result in a HTMLCollection of all <input>, <button>, <fieldset>, and <legend> within <form>.
function allFields(e) {
const io = this.elements;
...
Next, reference all form controls assigned [name="chx"] (all checkboxes) and collect them into a HTMLCollection then convert it into a real array. Do so for all [name="rang"] (all ranges) as well.
const chx = [...io.chx];
const rng = [...io.rng];
Then run each array through the Array method .every() which will return true if all elements in the array are true for a given conditional. The condition for the ranges is .value === '100' and for the checkboxes is .checked === true.
let allChecked = chx.every(c => c.checked === true);
let allMaxRange = rng.every(r => r.value === '100');
Finally compare allChecked and allMaxRange.
if (allChecked === true && allMaxRange === true) {
io.launch.disabled = false;
} else {
io.launch.disabled = true;
}
const form = document.forms[0];
form.onchange = allFields;
function allFields(e) {
const io = this.elements;
const chx = [...io.chx];
const rng = [...io.rng];
let allChecked = chx.every(c => c.checked === true);
let allMaxRange = rng.every(r => r.value === '100');
if (allChecked === true && allMaxRange === true) {
io.launch.disabled = false;
} else {
io.launch.disabled = true;
}
};
input,
button {
display: inline-block;
font-size: 100%;
line-height: 1.15;
}
button {
cursor: pointer;
}
fieldset {
height: max-content;
}
[type="range"] {
width: 80%;
}
[type="checkbox"] {
margin-top: -20px;
}
<form>
<fieldset>
<legend>
<button id='launch' type='button' disabled>Launch</button>
</legend>
<input name='chx' type='checkbox'>
<input name='rng' type='range' value='100'><br>
<input name='chx' type='checkbox' checked>
<input name='rng' type='range' value='100'><br>
<input name='chx' type='checkbox' checked>
<input name='rng' type='range' value='100'><br>
<input name='chx' type='checkbox' checked>
<input name='rng' type='range' value='100'><br>
<input name='chx' type='checkbox' checked>
<input name='rng' type='range' value='100'><br>
<input name='chx' type='checkbox' checked>
<input name='rng' type='range' value='100'><br>
</fieldset>
</form>
Try this approach :
You need to iterate over all checkbox elements as well as range elements.
Then use a flag variable to verify if all checkboxes/ranges are checked/max.
Use onchange/oninput event handlers. -> while loop is not necessary
I'm using vanilla js, and I'm stumped because there's very little code here, so I'm not sure where the problem lies. It may be a misunderstanding on my part on how the attribute works.
function changeState() {
const self = event.target
const parent = event.path[1]
if (self.type == "radio") {
console.log(self.id + " is " + self.checked)
}
}
<div id="usernames_buttons">
<input type="radio" name="usernames" id="usernames-bl" onclick="changeState()" checked>
<label for="usernames-bl">BL</label>
</input>
<input type="radio" name="usernames" id="usernames-wl" onclick="changeState()">
<label for="usernames-wl">WL</label>
</input>
<button data-toggle onclick="changeState()">OFF</button>
</div>
I paired everything down to just this code and ran it in a code pen to test, and the console.log will return true regardless of which option I am clicking. The expectation is that usernames-bl would return true and -wl would return false, but they return true whether the checked attribute is there or not.
You are invoking the changeState() on every click and i guess, as its a radio button, which will always give checked 'true' on click
I think you are doing it right minus the "Off" button should un-check both.. so I added this block:
if (self.type != "radio") {
document.getElementById("usernames-wl").checked = false;
document.getElementById("usernames-bl").checked = false;
}
function changeState() {
const self = event.target
const parent = event.path[1]
if (self.type != "radio") {
document.getElementById("usernames-wl").checked = false;
document.getElementById("usernames-bl").checked = false;
}
console.log("usernames-wl is " + document.getElementById("usernames-wl").checked)
console.log("usernames-bl is " + document.getElementById("usernames-bl").checked)
}
<div id="usernames_buttons">
<input type="radio" name="usernames" id="usernames-bl" onclick="changeState()" checked/>
<label for="usernames-bl">BL</label>
<input type="radio" name="usernames" id="usernames-wl" onclick="changeState()"/>
<label for="usernames-wl">WL</label>
<button data-toggle onclick="changeState()">OFF</button>
</div>
I've tried almost all the methods mentioned here and in other websites but still I'm stuck so that's why I'm asking it here.
I've created a form (with out <form></form> tags) in this form I'm creating 4 radios buttons using a while loop data is being pulled from a database.
To send data I'm using a JavaScript(Ajax) which is bound to a button click event.
Now I want to keep the submit button disabled until all the filed's are filled the last filed's are the radio buttons I'm tried to use many other ways to do this but nothing happened so any way below is code I'm using.
function checkUrole() {
var roles = document.getElementById("userRoles"),
btn = document.getElementById("submit"),
len = roles.length,
sel = null;
for(var i=0; i < len; i++){
if (roles.checked){
sel = roles[i].value;
}
}
if (sel === null){
document.getElementById("msgID").innerHTML = "9";
btn.disabled = true;
}else{
btn.disabled = false;
}
}
And this is my HTML
<label for="userRoles">User Role:</label><br>
<?php while ($row = $getUserRoleQuery -> fetch(PDO::FETCH_ASSOC)) { ?>
<input type="radio" id="userRoles" name="userRoles" value="<?php echo $row["urId"]; ?>" onmousedown="checkUrole()"><?php echo $row["userRole"]; }?>
<label id="msgID" hidden></label>
<div id="msg"></div>
Basically the HTML will create something like this,
<input type="radio" id="userRoles" name="userRoles" value="1" onmousedown="checkUrole()">Admin
<input type="radio" id="userRoles" name="userRoles" value="2" onmousedown="checkUrole()">Manager
<input type="radio" id="userRoles" name="userRoles" value="3" onmousedown="checkUrole()">Team Leader
<input type="radio" id="userRoles" name="userRoles" value="4" onmousedown="checkUrole()">User
I don't like write a code like this,
if(document.getElementById("userRoles1").checked{
something here;
}else if(document.getElementById("userRoles2").checked{
something here;
}else{
something here;
}
above I think makes the program a bit less dynamic 'cos if a new user role is added I've add a new IF to the loop.
So is there any way I solve this and I like to use JavaScript if can.
UPDATE: Thanks to #zer00ne I solved this problem and below is the finale working code hope this helps any one in the future as well.
My HTML:
<script language="JavaScript" type="text/javascript" src="../jScripts/userCreatFunctions.js">
<div id="userRoles">
<input type="radio" name="userRoles" value="1" checked>Admin
<input type="radio" name="userRoles" value="2">Manager
<input type="radio" name="userRoles" value="3">Team Leader
<input type="radio" name="userRoles" value="4">User
</div>
My JaveScript:
$(document).ready(function () {
/*Register the change element to #roles
|| When clicked...*/
//This code base was originally developed by zer00ne I'm using it under his permission
//Thanks man.
var form = document.getElementById('userRoles');
if (form){
form.addEventListener('change', function(e) {
/* Determine if the e.target (radio that's clicked)
|| is NOT e.currentTarget (#roles)
*/
if (e.target !== e.currentTarget) {
// Assign variable to e.target
var target = e.target;
// Reference the submit button
var btn = document.querySelector('[name=submit]');
// Enable submit button
btn.disabled = false;
// call rolrDist() passing the target,value
roleDist(target.value);
}
}, false);
}
function roleDist(rank) {
var display = document.getElementById("msg");
if (rank !== null) {
display.innerHTML = "All done! You can save";
} else {
display.innerHTML = "Please Select User Type";
}
}
});
Use the $(document).ready(function () {}) other wise the script get loaded before the DOM which leads to a NULL value making the script none functional.
Firstly, you don't need the id's on every input element. You can get an array of the button element by name using getElementsByName, here is an example of how you would do "something" based on one of those being checked:
JS (Using ES6)
const getRadioValue = (name) => {
const radios = document.getElementsByName(name);
let val;
Object.keys(radios).forEach((obj, i) => {
if (radios[i].checked) {
val = radios[i].value;
}
});
return val;
}
document.getElementById('form').addEventListener('change', (e) => {
getRadioValue('userRoles'); // value of checked radio button.
});
HTML
<div id="form">
<input type="radio" name="userRoles" value="1">Admin
<input type="radio" name="userRoles" value="2">Manager
<input type="radio" name="userRoles" value="3">Team Leader
<input type="radio" name="userRoles" value="4">User
</div>
JsFiddle Example
UPDATE - improved
A more efficient method would be using the Array.prototype.find() method, this is better because:
The find method executes the callback function once for each index of the array until it finds one where callback returns a true value. If such an element is found, find immediately returns the value of that element.
In other words, it doesn't need to iterate the entire Array, once we find what we want it returns.
Note: Use the below snippets within the change event mentioned above to retrieve the checked value.
JS (Using ES6)
const getCheckedRadioValue = (name) => {
const radios = document.getElementsByName(name);
try {
// calling .value without a "checked" property will throw an exception.
return Array.from(radios).find((r, i) => radios[i].checked).value
} catch(e) { }
}
getCheckedRadioValue('userRoles');
JsFiddle Example
JS (Without ES6)
function getCheckedRadioValue(name) {
var radios = document.getElementsByName(name);
var val;
for (var i = 0, len = radios.length; i < len; i++) {
if (radios[i].checked) {
val = radios[i].value;
break;
}
}
return val; // return value of checked radio or undefined if none checked
}
getCheckedRadioValue('userRoles');
JsFiddle Example
References
Array.prototype.forEach()
Array.from()
Array.prototype.find()
Not exactly sure what you are trying to do, so here is what I'm guessing:
Need to determine the value of a checked radio input
Need to enable a submit button that's determined by a checked radio
Need to effectively call upon other functions, run additional interactions, etc. depending on what was specifically checked.
Details are commented in Snippet
SNIPPET
// Reference #roles
var form = document.getElementById('roles');
/* Register the change element to #roles
|| When clicked...
*/
form.addEventListener('change', function(e) {
/* Determine if the e.target (radio that's clicked)
|| is NOT e.currentTarget (#roles)
*/
if (e.target !== e.currentTarget) {
// Assign variable to e.target
var target = e.target;
// Find the textNode next to target
var label = target.nextSibling;
// Reference the #display
var display = document.getElementById('display');
// Display the <label>s text and radio value
display.value = label.textContent + ' - Rank: ' + target.value;
// Reference the submit button
var btn = document.querySelector('[type=submit]');
// Enable submit button
btn.disabled = false;
// call rolrDist() passing the target,value
roleDist(target.value);
}
}, false);
function roleDist(rank) {
switch (rank) {
case '4':
alert('Rank 4 - Limited Access');
// Take user to landing page
break;
case '3':
alert('Rank 3 - Basic Access');
// Take user to dashboard
break;
case '2':
alert('Rank 2 - Advanced Access');
// Take user to database
break;
case '1':
alert('Rank 1 - Full Access');
// Take user to admin panel
break;
}
}
input,
output,
[type=submit] {
font: inherit;
cursor: pointer;
}
[type=submit] {
float: right;
}
<form id='roles'>
<input type="radio" name="role" value="1">Admin
<input type="radio" name="role" value="2">Manager
<input type="radio" name="role" value="3">Team Leader
<input type="radio" name="role" value="4">User
</form>
<br/>
<label for='display'>Role: </label>
<!--
Since #display and submit button are outside of
the <form>, using the form attribute and the
<form>'s #id as the value establishes an
association between them and <form>
-->
<output id='display' form='roles'></output>
<br/>
<input type='submit' form='roles' disabled>
There is very basic mistake in your markup you should not use elements with same id's in
You can use class instead of id (give class to radioboxes)
document.getElementsByClassName("userRoles")
<input type="radio" class="userRoles" name="userRoles" value="1" onmousedown="checkUrole()">Admin
Rest of your code seems ok
I have a checkbox in a form and I'd like it to work according to following scenario:
if someone checks it, the value of a textfield (totalCost) should be set to 10.
then, if I go back and uncheck it, a function calculate() sets the value of totalCost according to other parameters in the form.
So basically, I need the part where, when I check the checkbox I do one thing and when I uncheck it, I do another.
Pure javascript:
const checkbox = document.getElementById('myCheckbox')
checkbox.addEventListener('change', (event) => {
if (event.currentTarget.checked) {
alert('checked');
} else {
alert('not checked');
}
})
My Checkbox: <input id="myCheckbox" type="checkbox" />
function calc()
{
if (document.getElementById('xxx').checked)
{
document.getElementById('totalCost').value = 10;
} else {
calculate();
}
}
HTML
<input type="checkbox" id="xxx" name="xxx" onclick="calc();"/>
If you are using jQuery.. then I can suggest the following:
NOTE: I made some assumption here
$('#my_checkbox').click(function(){
if($(this).is(':checked')){
$('input[name="totalCost"]').val(10);
} else {
calculate();
}
});
Use an onclick event, because every click on a checkbox actually changes it.
The following solution makes use of jquery. Let's assume you have a checkbox with id of checkboxId.
const checkbox = $("#checkboxId");
checkbox.change(function(event) {
var checkbox = event.target;
if (checkbox.checked) {
//Checkbox has been checked
} else {
//Checkbox has been unchecked
}
});
HTML:
<input type="checkbox" onchange="handleChange(event)">
JS:
function handleChange(e) {
const {checked} = e.target;
}
Reference the checkbox by it's id and not with the #
Assign the function to the onclick attribute rather than using the change attribute
var checkbox = $("save_" + fieldName);
checkbox.onclick = function(event) {
var checkbox = event.target;
if (checkbox.checked) {
//Checkbox has been checked
} else {
//Checkbox has been unchecked
}
};
Javascript
// on toggle method
// to check status of checkbox
function onToggle() {
// check if checkbox is checked
if (document.querySelector('#my-checkbox').checked) {
// if checked
console.log('checked');
} else {
// if unchecked
console.log('unchecked');
}
}
HTML
<input id="my-checkbox" type="checkbox" onclick="onToggle()">
try
totalCost.value = checkbox.checked ? 10 : calculate();
function change(checkbox) {
totalCost.value = checkbox.checked ? 10 : calculate();
}
function calculate() {
return other.value*2;
}
input { display: block}
Checkbox: <input type="checkbox" onclick="change(this)"/>
Total cost: <input id="totalCost" type="number" value=5 />
Other: <input id="other" type="number" value=7 />
I know this seems like noob answer but I'm putting it here so that it can help others in the future.
Suppose you are building a table with a foreach loop. And at the same time adding checkboxes at the end.
<!-- Begin Loop-->
<tr>
<td><?=$criteria?></td>
<td><?=$indicator?></td>
<td><?=$target?></td>
<td>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="active" value="<?=$id?>" <?=$status?'checked':''?>>
<!-- mark as 'checked' if checkbox was selected on a previous save -->
</div>
</td>
</tr>
<!-- End of Loop -->
You place a button below the table with a hidden input:
<form method="post" action="/goalobj-review" id="goalobj">
<!-- we retrieve saved checkboxes & concatenate them into a string separated by commas.i.e. $saved_data = "1,2,3"; -->
<input type="hidden" name="result" id="selected" value="<?= $saved_data ?>>
<button type="submit" class="btn btn-info" form="goalobj">Submit Changes</button>
</form>
You can write your script like so:
<script type="text/javascript">
var checkboxes = document.getElementsByClassName('form-check-input');
var i;
var tid = setInterval(function () {
if (document.readyState !== "complete") {
return;
}
clearInterval(tid);
for(i=0;i<checkboxes.length;i++){
checkboxes[i].addEventListener('click',checkBoxValue);
}
},100);
function checkBoxValue(event) {
var selected = document.querySelector("input[id=selected]");
var result = 0;
if(this.checked) {
if(selected.value.length > 0) {
result = selected.value + "," + this.value;
document.querySelector("input[id=selected]").value = result;
} else {
result = this.value;
document.querySelector("input[id=selected]").value = result;
}
}
if(! this.checked) {
// trigger if unchecked. if checkbox is marked as 'checked' from a previous saved is deselected, this will also remove its corresponding value from our hidden input.
var compact = selected.value.split(","); // split string into array
var index = compact.indexOf(this.value); // return index of our selected checkbox
compact.splice(index,1); // removes 1 item at specified index
var newValue = compact.join(",") // returns a new string
document.querySelector("input[id=selected]").value = newValue;
}
}
</script>
The ids of your checkboxes will be submitted as a string "1,2" within the result variable. You can then break it up at the controller level however you want.