I have a form with many text-input-fields and checkboxes. Whenever a checkbox is checked, all text-input fields and all other checkboxes (exept the one that was checked) should be disabled. After unchecking this checkbox, all disabled fields should be enabled again.
This works with the following code (shown are only the first 3 lines):
<form id="myForm">
Checkbox 1: <input type="checkbox" name="checkbox1" id="checkboxOne" onclick="enableDisableAll();" />
<input type="text" id="id1" name="name1" /><br>
Checkbox 2: <input type="checkbox" name="checkbox2" id="checkboxTwo" onclick="enableDisableAll();" />
<input type="text" id="id2" name="name2" /><br>
Checkbox 3: <input type="checkbox" name="checkbox3" id="checkboxThree" onclick="enableDisableAll();" />
<input type="text" id="id3" name="name3" /><br>
</form>
function enableDisableAll() {
cb1 = document.getElementById('checkboxOne').checked;
cb2 = document.getElementById('checkboxTwo').checked;
cb3 = document.getElementById('checkboxThree').checked;
document.getElementById('checkboxOne').disabled = (cb2 || cb3);
document.getElementById('id1').disabled = (cb1 || cb2 || cb3);
document.getElementById('checkboxTwo').disabled = (cb1 || cb3);
document.getElementById('id2').disabled = (cb1 || cb2 || cb3);
document.getElementById('checkboxThree').disabled = (cb1 || cb2);
document.getElementById('id3').disabled = (cb1 || cb2 || cb3);
}
Since the code becomes confusing with many checkboxes (cb1 || cb2 || cb3 || ....... cb(n)), I wonder if there would be a more elegant possibility to do this, e.g.:
function enableDisableAll() {
cb1 = document.getElementById('checkboxOne').checked;
cb2 = document.getElementById('checkboxTwo').checked;
cb3 = document.getElementById('checkboxThree').checked;
var cb_array = [];
cb_array.push("cb1");
cb_array.push("cb2");
var cb_array_imploded = cb_array.join(" || ");
document.getElementById('id1').disabled = (cb_array_imploded);
Unfortunately, this does not work.
Does anyone have a simple solution for my problem?
select all the form elements and loop through and check for id same as clicked element id.if so don't disabled it.
function enableDisableAll(e) {
var own = e;
var form = document.getElementById("myForm");
var elements = form.elements;
for (var i = 0 ; i < elements.length ; i++) {
if(own !== elements[i] ){
if(own.checked == true){
elements[i].disabled = true;
}else{
elements[i].disabled = false;
}
}
}
}
function clearAll(){
document.getElementById("myForm").reset();
}
<form id="myForm">
Checkbox 1: <input type="checkbox" name="checkbox1" id="checkboxOne" onclick="enableDisableAll(this);" />
<input type="text" id="id1" name="name1" /><br>
Checkbox 2: <input type="checkbox" name="checkbox2" id="checkboxTwo" onclick="enableDisableAll(this);" />
<input type="text" id="id2" name="name2" /><br>
Checkbox 3: <input type="checkbox" name="checkbox3" id="checkboxThree" onclick="enableDisableAll(this);" />
<input type="text" id="id3" name="name3" /><br>
</form>
<input class="field button2" type="button" value="Clear form" size="10" onclick="clearAll(this);">
Update : To clear all the form fields
document.getElementById("myForm").reset();
One possible approach is the following; though note that I amended your HTML, wrapping the <input type="checkbox"> elements in a parent <label> element, and removing the unnecessary <br /> elements along with the obtrusive in-line event-handlers in the HTML:
// a named function bound to an element via
// via JavaScript; the 'event' argument
// is passed automatically from the
// EventTarget.addEventListener() method:
function disableIfChecked(event) {
// the event.target node is the node upon which
// the listened-for event was originally triggered:
let target = event.target;
// 'this' is also passed from the
// EventTarget.addEventListener() method; here
// retrieved all <input> elements within the
// <form> (the 'this'), convert that NodeList
// explicitly to an Array and then filter that
// Array using an Arrow function:
Array.from(this.querySelectorAll('input')).filter(
// we retain only those elements ('el') in the Array
// which are not equal to, and therefore are not, the
// changed element:
el => el !== target
// iterating over the filtered collection:
).forEach(
// each <input> element remaining in the collection
// will be disabled if the changed element is clicked,
// or enabled if the changed element is no longer clicked:
el => el.disabled = target.checked
);
}
document.querySelector('#myForm').addEventListener('change', disableIfChecked);
/* Selecting the <label> element that follows
an <input> element: */
input+label::before {
/* Adding a line-feed character using the CSS
'content' property of the pseudo-element
to force each <label> to a new-line: */
content: '\A';
display: block;
}
<form id="myForm">
<!-- the label element associates the text with the enclosed
input, so clicking the text focuses that input element: -->
<label>Checkbox 1: <input type="checkbox" name="checkbox1" id="checkboxOne" /></label>
<input type="text" id="id1" name="name1" />
<label>Checkbox 2: <input type="checkbox" name="checkbox2" id="checkboxTwo" /></label>
<input type="text" id="id2" name="name3" />
<label>Checkbox 3: <input type="checkbox" name="checkbox3" id="checkboxThree" /></label>
<input type="text" id="id3" name="name3" />
</form>
JS Fiddles: commented, uncommented
In order to support browsers without support for ES6, the following is an alternative approach doing the same thing:
// a named function bound to an element via
// via JavaScript; the 'event' argument
// is passed automatically from the
// EventTarget.addEventListener() method:
function disableIfChecked(event) {
// the event.target node is the node upon which
// the listened-for event was originally triggered:
let target = event.target;
// 'this' is also passed from the
// EventTarget.addEventListener() method; here
// retrieved all <input> elements within the
// <form> (the 'this'), convert that NodeList
// explicitly to an Array by treating the NodeList
// as an Array, using Function.prototype.call(),
// and Array.prototype.slice():
Array.prototype.slice.call(
this.querySelectorAll('input')
).filter(function(el) {
// we retain only those elements ('el') in the Array
// which are not equal to, and therefore are not, the
// changed element:
return el !== target;
// iterating over the filtered collection:
}).forEach(function(el) {
// each <input> element remaining in the collection
// will be disabled if the changed element is clicked,
// or enabled if the changed element is no longer clicked:
el.disabled = target.checked;
});
}
document.querySelector('#myForm').addEventListener('change', disableIfChecked);
/* Selecting the <label> element that follows
an <input> element: */
input+label::before {
/* Adding a line-feed character using the CSS
'content' property of the pseudo-element
to force each <label> to a new-line: */
content: '\A';
display: block;
}
<form id="myForm">
<!-- the label element associates the text with the enclosed
input, so clicking the text focuses that input element: -->
<label>Checkbox 1: <input type="checkbox" name="checkbox1" id="checkboxOne" /></label>
<input type="text" id="id1" name="name1" />
<label>Checkbox 2: <input type="checkbox" name="checkbox2" id="checkboxTwo" /></label>
<input type="text" id="id2" name="name3" />
<label>Checkbox 3: <input type="checkbox" name="checkbox3" id="checkboxThree" /></label>
<input type="text" id="id3" name="name3" />
</form>
JS Fiddles.
References:
Array.from().
Array.prototype.filter().
Array.prototype.forEach().
Document.querySelectorAll().
Element.querySelectorAll().
JavaScript Arrow Functions.
It's usually best to use onchange instead of onclick event on inputs such as checkboxes, radiobuttons, or selects.
In order to make a general solution for as many inputs as you need, it's best to use document.querySelectorAll to fetch all inputs within the form. You can then iterate over all inputs and set their disabled property to the checked value of the targeted checkbox.
Solution snippet below:
function enableDisableAll(event) {
var allInputs = document.querySelectorAll('#myForm input');
allInputs.forEach(function(input) {
if (input !== event.target) {
input.disabled = event.target.checked;
}
});
}
<form id="myForm">
Checkbox 1: <input type="checkbox" name="checkbox1" id="checkboxOne" onchange="enableDisableAll(event);" />
<input type="text" id="id1" name="name1" /><br> Checkbox 2: <input type="checkbox" name="checkbox2" id="checkboxTwo" onchange="enableDisableAll(event);" />
<input type="text" id="id2" name="name2" /><br> Checkbox 3: <input type="checkbox" name="checkbox3" id="checkboxThree" onchange="enableDisableAll(event);" />
<input type="text" id="id3" name="name3" /><br>
</form>
An important detail here is that if you want to assign a typical event handler function directly to an HTML attribute, the function must have a single parameter explicitly named event. It is however recommended to assign event handlers in javascript and not in HTML. The syntax for that would be myCheckbox.addEventListener('change', enableDisableAll);
You may want to add listeners to every checkbox, by iterating over a selector of all checkboxes.
Related
I have an element in my page:
<form>
<div data-id="x">
<label>field 1</label>
<input name="field1" type="text" value="Foo" />
<label>field 2</label>
<input name="field2" type="number" value="5" />
</div>
<div data-id="y">
<label>field 1</label>
<input name="field1" type="text" value="Foo" />
<label>field 2</label>
<input name="field2" type="number" value="5" />
</div>
...other 100 inputs...
</form>
I'm looking for a javascript script like that:
var theElement = document.querySelector('[data-id="x"]');
var myObject = theElement.toObject();
And the object must looks like
{"field1":"Foo","field2":5}
I can't use the FormData strategy because I need a very small set of data from a very big form, but it is like a "partial FormData".
I'm asking if exists a standard method to convert the content of an HTMLElement in an object like for the FormData.
PS: i can use also the data-attribute if necessary
Actually there is no standard quicky method to do this task.
The solution is iterate over inputs and selects:
<script>
let myObj = {};
let element = document.querySelector('[data-id="x"]');
element.querySelectorAll('input').forEach(el=> {
// check the type
// the property is : el.name
// the value must be : el.value for text/number/email...
// the value for the type="checkbox" is according to checked attribute
});
element.querySelectorAll('select').forEach(sel=> {
// if multiple choise => create an array of selected options
// if single => check the selected option's value
});
</script>
This is the code i've used (simplified)
I am building a page where user will be able to choose various goods from a category ( e milk/fruit...)
This is done in a form.
Then, I send them to server and do some processing.
<div>
<div><input type="checkbox" name="milk" value="yogurt1"/>yogurt1</div>
<div><input type="checkbox" name="milk" value="yogurt2"/>yogurt2</div>
<div><input type="checkbox" name="milk" value="yogurt3"/>yogurt3</div>
</div>
<div>
<div><input type="checkbox" name="fruit" value="apple"/>apple</div>
<div><input type="checkbox" name="fruit" value="pear"/>pear</div>
<div><input type="checkbox" name="fruit" value="melon"/>melon</div>
</div>
....
Q: How can I validate that the user has chosen at least 1 product from each category ( i.e. at list 1 milk item and at least 1 fruit item were checked)?
You can use attribute selector with :checked pseudo-selector as follow:
if ($(':checkbox[name="milk"]:checked').length > 0) {
alert('Min 1 checked');
}
For multiple groups:
if ($(':checkbox[name="milk"]:checked').length == 0 || $(':checkbox[name="fruit"]:checked').length == 0 || ...) {
alert('Please check at least one checkbox from group');
}
Demo
You should check length of selected values.
$("#check").on("click", function() {
if ($("[name=\"milk\"]:checked").length > 0 && $("[name=\"fruit\"]:checked").length > 0) {
alert("success");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div>
<div>
<input type="checkbox" name="milk" value="yogurt1" />yogurt1</div>
<div>
<input type="checkbox" name="milk" value="yogurt2" />yogurt2</div>
<div>
<input type="checkbox" name="milk" value="yogurt3" />yogurt3</div>
</div>
<div>
<div>
<input type="checkbox" name="fruit" value="apple" />apple</div>
<div>
<input type="checkbox" name="fruit" value="pear" />pear</div>
<div>
<input type="checkbox" name="fruit" value="melon" />melon</div>
</div>
<div id="check">check</div>
Rather than hard-coding every checkbox name in your validation, you could also create a more dynamic solution that will handle any name.
This process I would suggest is best explained by the comments in this snippet demo below:
// execute function on dom-ready
$(function(){
// bind an event handler to the form's 'submit' event
$('#myForm').on('submit', function(e){
// get all checkboxes within our form
var $checkboxes = $('#myForm input[type="checkbox"]');
// create an object to use as a map of checkbox names and whether or not one of them is checked
var checkboxMap = {};
// iterate over all checkboxes
$checkboxes.each(function(i, el){
// get the name of this checkbox
var name = el.name;
// if our checkbox map has a truthy value at the key 'name'
// then keep that value, otherwise assign a value based on whether or not this checkbox is checked
checkboxMap[name] = checkboxMap[name] || el.checked;
});
// iterate over all names in our checkbox map
for(var name in checkboxMap){
// if we find a name without a truthy value, that means a there was no option chosen for that checkbox
if(!checkboxMap[name]){
// give an error alert and stop the form from being submitted
alert('You must choose at least one ' + name);
e.preventDefault();
return false;
}
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<form id="myForm">
<div>
<div><input type="checkbox" name="milk" value="yogurt1"/>yogurt1</div>
<div><input type="checkbox" name="milk" value="yogurt2"/>yogurt2</div>
<div><input type="checkbox" name="milk" value="yogurt3"/>yogurt3</div>
</div>
<div>
<div><input type="checkbox" name="fruit" value="apple"/>apple</div>
<div><input type="checkbox" name="fruit" value="pear"/>pear</div>
<div><input type="checkbox" name="fruit" value="melon"/>melon</div>
</div>
<input type="submit" />
</form>
I have a website where there are five checkboxes, a div that contains another divs which each div contains five input hidden that have a value 1 or empty. That value comes from DB.
That's an example to represent the div container with the divs:
<input checkbox value="a">
<input checkbox value="b">
<input checkbox value="c">
<input checkbox value="d">
<input checkbox value="e">
<div class="container">
<div class="content" data-name="combine">
<input type="hidden" value="" data-name="a" />
<input type="hidden" value="" data-name="b" />
<input type="hidden" value="" data-name="c" />
<input type="hidden" value="" data-name="d" />
<input type="hidden" value="" data-name="e" />
</div>
<div class="content" data-name="combine">
<input type="hidden" value="1" data-name="a" />
<input type="hidden" value="" data-name="b" />
<input type="hidden" value="" data-name="c" />
<input type="hidden" value="1" data-name="d" />
<input type="hidden" value="" data-name="e" />
</div>
</div>
In the javascript code i have this snippet:
if(elementLength > 0) {
$("[data-name='combine'] div.tagsProds").each(function() {
var element = $(this);
$.each(enabledChecks,function(i, v) {
if(element.find("input[name='"+v+"']").val() == "") {
element.append("<div class='blocked'></div>");
element.unbind("click");
element.addClass("js_noSortable");
}
});
});
}
The javascript first checks if the div.container has childs and if it has childs the code iterates each child. On each child i iterate the five each checkbox (enabledChecks) and i see if the input hidden are empty. What i need if that if the five input are empty then append the `div.blocked'.
As i don't have enough reputation to write a comment i write an answer.
First, i think that your answer is quite interesting if you're looking to find a way using a jQuery function, but as i don't know any function to do this i think that you can create an array() and when you check if the input has empty value push it to the array, when the loop finishes you check the length of the array() and if it matches with the number of your checkboxes then append the .blocked
If I understand the question correctly, you want to find divs matching some selector that have no child input elements with non-empty values. The .filter method seems like a good fit here:
$("[data-name='"+name+"'] div.tagsProds")
.filter(function() {
// assert that at least one child input has a value
var $inputsWithValue = $(this).find("input[name='avail_" + v + "'][value!='']");
return $inputsWithValue.length === 0;
})
.each(function() {
// now act on those value-less divs
$(this)
.append("<div class='blocked'></div>")
.addClass("js_noSortable")
.unbind("click");
});
Another selector-only option might look like:
$("[data-name='"+name+"'] div.tagsProds:not(:has(input[name='avail_" + v + "'][value!='']))")
.each(function() {
// now act on those value-less divs
$(this)
.append("<div class='blocked'></div>")
.addClass("js_noSortable")
.unbind("click");
});
JSFiddle: http://jsfiddle.net/nrabinowitz/vrx2wk8g/
Note that the examples above follow the selectors in your sample code, but won't work against your sample markup.
I am trying to update the HTML5 placeholder attribute when the a radio button is selected. I'm not using JQuery, so would prefer an inline JavaScript solution. I know I'm missing something simple, but am trying to teach myself!
<script type="text/javascript">
function ModifyPlaceHolder1 () {
var input = document.getElementById ("MyQuery");
input.placeholder = "Search books e.g. Harry Potter";
}
function ModifyPlaceHolder2 () {
var input = document.getElementById ("MyQuery");
input.placeholder = "Search journals e.g. New Scientist";
}
</script>
<input type="text" id="MyQuery" placeholder="Search resources" name="q" />
<input type="radio" value="" id="All" name="s.cmd" checked="checked" />
<label for="All">All</label>
<input type="radio" onclick="ModifyPlaceHolder1 ()" value="" id="Books" name="s.cmd" checked="checked" />
<label for="Books">Books</label>
<input type="radio" onclick="ModifyPlaceHolder2 ()" value="" id="Journals" name="s.cmd" checked="checked" />
<label for="Journals">Journals</label>
Here's a way to do this without any inline JS. A wee bit cleaner, and easier to track (IMO).
<input type="text" id="MyQuery" placeholder="Search resources" name="q" />
<input type="radio" value="" id="All" name="s.cmd" checked="checked" />
<label for="All">All</label>
<input type="radio" value="" id="Books" name="s.cmd" checked="checked" />
<label for="Books">Books</label>
<input type="radio" value="" id="Journals" name="s.cmd" checked="checked" />
<label for="Journals">Journals</label>
var books = document.getElementById("Books");
var journals = document.getElementById("Journals");
var input = document.getElementById("MyQuery");
books.onclick = function() {
input.placeholder = "Search books e.g. Harry Potter";
}
journals.onclick = function() {
input.placeholder = "Search journals e.g. New Scientist";
}
I would program it with a single function as below:
<script>
function ModifyPlaceHolder(element) {
var data = {
All: 'Search resources',
Books: 'Search books e.g. Harry Potter',
Journals: 'Search journals e.g. New Scientist'
};
var input = element.form.MyQuery;
input.placeholder = data[element.id];
}
</script>
<form>
<input type="text" id="MyQuery" placeholder="Search resources" name="q">
<label for="All"><input type="radio" onclick="ModifyPlaceHolder(this)" id="All" name="s.cmd" checked> All</label>
<label for="Books"><input type="radio" onclick="ModifyPlaceHolder(this)" id="Books" name="s.cmd"> Books</label>
<label for="Journals"><input type="radio" onclick="ModifyPlaceHolder(this)" id="Journals" name="s.cmd"> Journals</label>
</form>
Note that:
Not all browsers in use support the placeholder attribtue
Label elements should really wrap the control they apply to, otherwise some browsers won't correctly associate them. Wrapping also means the label acts as part of the button, so clicking on the lable checks the button too.
Only one radio button can be checked at a time, so only set one as the default checked.
Putting the controls in a form makes them easier to access.
When you see a string of identical listeners that are all contained in one element, you can look to putting a single listener on a parent element. Search for "event delegation".
Try this:
<script>
function ModifyPlaceHolder(element) {
var data = {
All: 'Search resources',
Books: 'Search books e.g. Harry Potter',
Journals: 'Search journals e.g. New Scientist'
};
var input = document.getElementById("MyQuery");
input.placeholder = data[element.id];
}
</script>
Am trying to get the value of the hidden input fields on every click of a radio button. I have just posted a single div. I have a multiple div with same structure. I have successfully obtained the value of radio button but I want to get the value of hidden input now.
<div class="QA">
<h1> First Question</h1>
<input type="radio" id="check" name="q" value="A">Options 1</input>
<input type="radio" id="check" name="q" value="B">Options 2</input>
<input type="radio" id="check" name="q" value="C">Options 3</input>
<input type="radio" id="check" name="q" value="D">Options 4</input>
<input type="hidden" id="result" value="B" />
<br/>
<div id="result"></div>
</div>
<script>
$(document).ready(function() {
$("input:radio").change(function() {
checkResult(this);
});
});
function checkResult(el)
{
$this=$(el).parent("div.QA");
$this.slideUp();
}
</script>
Maybe you could try removing the hidden input entirely and indicate the correct answer using a data-* attribute. Something like:
<div class="QA" data-answer="B">
Then in your checkResult function you could retrieve this value using
function checkResult(el)
{
$this=$(el).parent("div.QA");
var answer = $this.data("answer");
$this.slideUp();
}
function checkResult(el)
{
$this = $(el).parents("div.QA");
$this.slideUp();
var x = $this.find('#result').val(); //find value of hidden field in parent div
}
Change your markup
multiple id's should not be used. Use class instead.
<input type="radio" id="check" name="q" value="A">Options 1</input>
to
<input type="radio" class="check" name="q" value="A">Options 1</input>
var $hidden=$(el).siblings("input[type='hidden']");
BTW you have lot of elements with same ID, not good
You can get the value of the hidden element by it's id.
var hiddenValue = $("#result").val();
You can use this in hidden function
function checkResult(el)
{
var hiddenValue = $("#result").val();
alert(hiddenValue);
}