Hi I've got a form with nested Checkbox on three level
With Jquery I need to checked/uncheked all the children when I check a parent level... and of course uncheck the parent if at least one of the children is uncheck
I try but never success that's why I'm calling your help :)
Many thanks to all
My html code :
Demo here : http://jsfiddle.net/SENV8/86/
<fieldset class="floral">
<input type="checkbox" class="familybox cbox">
<label>Level 1</label>
<ul class="valuelist">
<li>
<input type="checkbox" class="cbox mainoption">
<label>Level 2</label>
<ul class="suboption">
<li>
<input type="checkbox" class="cbox">
<label>Level 3</label>
</li>
</ul>
<ul class="suboption">
<li>
<input type="checkbox" class="cbox">
<label>Level 3</label>
</li>
</ul>
</li>
<li>
<input type="checkbox" class="cbox mainoption">
<label>Level 2</label>
<ul class="suboption">
<li>
<input type="checkbox" class="cbox">
<label>Level 3</label>
</li>
</ul>
<ul class="suboption">
<li>
<input type="checkbox" class="cbox">
<label>Level 3</label>
</li>
</ul>
</li>
</ul>
</fieldset>
EDIT :
I'm here with my script:
$('.familybox').change(function() {
var getparent = $(this).closest('fieldset').attr('class');
if($('.'+getparent+' .familybox').is(':checked')){
$('.'+getparent+' .valuelist input:checkbox').prop('checked', true);
} else if($('.'+getparent+' .familybox').not(':checked')) {
$('.'+getparent+' .valuelist input:checkbox').prop('checked', false);
}
});
See I have Implemented your requirement.
It is needed to make some changes in HTML which I have did in JSfiddle.
Total Jquery script is as follow:
<script type="text/javascript">
$(document).ready(function () {
$.extend($.expr[':'], {
unchecked: function (obj) {
return ((obj.type == 'checkbox' || obj.type == 'radio') && !$(obj).is(':checked'));
}
});
$(".floral input:checkbox").live('change', function () {
$(this).next('ul').find('input:checkbox').prop('checked', $(this).prop("checked"));
for (var i = $('.floral').find('ul').length - 1; i >= 0; i--) {
$('.floral').find('ul:eq(' + i + ')').prev('input:checkbox').prop('checked', function () {
return $(this).next('ul').find('input:unchecked').length === 0 ? true : false;
});
}
});
});
</script>
To see live demo:
JSFiddle
Related
When I click on Select, a box opens and we select many options, including father and child.When options are selected
After selection, immediately display the ID numbers on the input. When we click OK, the box will be hidden. I want each of the boxes to be done separately in the input .This is My Html:
<button class="btn-select">Select one ...</button>
<div class="box" style="display:none">
<input type="checkbox" class="checkbox" value="1">Check Box 1
<input type="checkbox" class="checkbox" value="2">Check Box 2
<input type="text" class="input input-1" value="">
<button class="btn-ok">Ok</button>
</div>
<button class="btn-select">Select Two (Father/Children) ...</button>
<div class="box" style="display:none">
<ul class="father">
<li>
<input type="checkbox" class="checkbox" value="1">Part 1
<ul class="children">
<li><input type="checkbox" class="checkbox" value="5">Check Box 5</li>
</ul></li>
<li>
<input type="checkbox" class="checkbox" value="2">Part 2
<ul class="children">
<li><input type="checkbox" class="checkbox" value="7">Check Box 7</li>
<li><input type="checkbox" class="checkbox" value="8">Check Box 8</li>
</ul></li></ul>
<input type="text" class="input input-2" value="">
<button class="btn-ok">Ok</button>
</div>
.
...Select Three...
..Select Four..
..
.
This is My JS (Children and Father):
handleChildren = function() {
var $checkbox = $(this);
var $checkboxChildren = $checkbox.parent();
$checkboxChildren.each(function() {
if ($checkbox.is(":checked")) {
$(this).prop("checked", "checked");
} else {
$(this).removeProp("checked");
}
});
};
handleParents = function(current) {
var $parent = $(current).closest(".children").closest("li").find("> input[type=checkbox]");
if ($parent.parent().find(".children input[type=checkbox]:checked").length > 0) {
$parent.prop("checked", "checked");
} else {
$parent.removeProp("checked");
}
handleParents($parent);
}
$("ul.father").find("input[type=checkbox]").each(function() {
$(input).on("click", handleChildren);
$(input).on("click", function() {
handleParents(this);
});
});
This is My JS:
$(document).on('click', '.btn-ok', function(){
$('.box').hide()
});
$(document).on('click', '.btn-select', function(){
$('.box').hide()
$(this).next().show();
});
$(".checkbox").change(function() {
var text = "";
$(".checkbox:checked").each(function() {
text += $(this).val() + ",";
});
text = text.substring(0, text.length - 1);
$(this).next().val(text);
});
Now an error is shown by the console that says:
Uncaught InternalError: too much recursion
closest file:///var/www/html/jquey.js:1
Your handleParents calls itself unconditionally.
I have an ul/li list
<ul id="browser" class="filetree">
<li>
<input type="checkbox" checked />
<a>whatever link1</a>
</li>
<li>
<input type="checkbox" checked />
<a>whatever link3</a>
</li>
<li>
<input type="checkbox"/>
<a>whatever link2</a>
<ul>
<li>
<input type="checkbox" checked />
<a>whatever link4</a>
</li>
</ul>
</li>
</ul>
I'm looking to get the HTML representing the whole list, only when the checkbox are checked using javascript and/or jquery.
Would anyone by chance have an idea ?
Thanks.
Not sure I understand the question fully but here's an example. This only selects a list (so only whatever link2 will trigger it), however it can be changed to select the anchor if that's necessary.
const mainList = document.getElementById('browser');
mainList.addEventListener('click', (e) => {
if (e.target.type === 'checkbox') {
const list = [...document.querySelectorAll('li > input:checked ~ ul')];
const selectedMarkup = document.getElementById('selectedMarkup');
selectedMarkup.innerHTML = list.map(el => el.innerHTML).join('');
}
})
<ul id="browser" class="filetree">
<li>
<input type="checkbox" checked />
<a>whatever link1</a>
</li>
<li>
<input type="checkbox" checked />
<a>whatever link3</a>
</li>
<li>
<input type="checkbox"/>
<a>whatever link2</a>
<ul>
<li>
<input type="checkbox" checked />
<a>whatever link4</a>
</li>
</ul>
</li>
</ul>
Selected Markup
<div id='selectedMarkup'>
</div>
This assigns the html to s.
Not sure what you want to do with it after that.
$('input[type="checkbox"]').onclick (
if($(this).checked)
s=$(this).ancestor('#browser').html();
)
try to push class on tick of checkbox in li.
e.g onCheck => <li class='checked'>
Then get all element who are having class 'checked' using jquery
thanks for the help everyone, I solved it. Every answer helped :)
For reference, my question wasn't clear at all, here what I was trying to do:
var domString = "<ul>";
function run() {
var mainTree = document.getElementById('browser');
getDom(mainTree);
domString += "</ul>";
console.log(domString);
document.getElementById("result").innerHTML = domString;
domString = "<ul>";
}
function getDom(tree) {
var children = tree.children;
for (var i = 0; i < children.length; i++) {
if (children[i].className === "list") {
var liChildren = children[i].children;
if (liChildren[0].checked == true) {
domString += children[i].outerHTML;
}
} else {
var liChildren = children[i].children;
if (liChildren[0].checked == true) {
domString += "<li class=\"site\">";
domString += liChildren[0].outerHTML;
domString += liChildren[1].outerHTML;
domString += "<ul>";
getDom(liChildren[2]);
domString += "</ul>"
domString += "</li>"
}
}
}
}
<ul id="browser" class="filetree">
<li class="list">
<input class="check" type="checkbox" checked/>
<a>whatever link1</a>
</li>
<li class="list">
<input class="check" type="checkbox" />
<a>whatever link2</a>
</li>
<li class="site">
<input class="check" type="checkbox" checked/>
<a>whatever link3</a>
<ul>
<li class="list">
<input class="check" type="checkbox" checked />
<a>whatever link4</a>
</li>
<li class="list">
<input class="check" type="checkbox" />
<a>whatever link5</a>
</li>
</ul>
</li>
</ul>
<button onclick="run()">Click</button>
<p>--------------------</p>
<div id="result"></div>
It's not optimal at all (and ugly at best, syntax wise) but it'll do for now. I'd be interested in hearing others better solutions though.
Have a nice day.
The idea is to filter divs by comparing dynamically generated classes for divs and dynamically generated id's for checkboxes, where only divs with classes matching id's of checked checkboxes would show.
First subnav filters everything fine. However, subnav2 dosen't do anything.
Simplified html of it
<div class="itemswrap">
<div class="inditem dynamic1 dynamic12"></div>
<div class="inditem dynamic2 dynamic22"></div>
<div class="inditem dynamic3 dynamic32"></div>
<div class="inditem dynamic2 dynamic42"></div>
</div>
<ul class="subnav">
<li class="lifilter">
<input type="checkbox" class="filtercheck" id="dynamic1" />
<label for="dynamic1">whatever label</label>
</li>
<li class="lifilter">
<input type="checkbox" class="filtercheck" id="dynamic2" />
<label for="dynamic1">whatever label</label>
</li>
<li class="lifilter">
<input type="checkbox" class="filtercheck" id="dynamic3" />
<label for="dynamic1">whatever label</label>
</li>
</ul>
<ul class="subnav2">
<li class="lifilter2">
<input type="checkbox" class="filtercheck2" id="dynamic12" />
<label for="dynamic12">whatever label</label>
</li>
<li class="lifilter2">
<input type="checkbox" class="filtercheck2" id="dynamic22" />
<label for="dynamic12">whatever label</label>
</li>
<li class="lifilter2">
<input type="checkbox2" class="filtercheck2" id="dynamic32" />
<label for="dynamic12">whatever label</label>
</li>
</ul>
And the js i've got so far.
var $filters = $('.filtercheck').change(function() {
var $items = $('.inditem').hide();
var filters = $filters.filter(':checked').map(function() {
return '.' + this.id;
}).get();
if (filters.length) {
$items.filter(filters.join()).show();
} else {
$items.show();
}
});
var $filtersb = $('.filtercheck2').change(function() {
var $itemsb = $('.inditem').hide();
var filtersb = $filtersb.filter(':checked').map(function() {
return '.' + this.id;
}).get();
if (filtersb.length) {
$itemsb.filter(filters.join()).show();
} else {
$itemsb.show();
}
});
I see that you fixed it but I had created a jsfiddle for your problem, akin to one I had to face in another project. Basically, you create a string from the checked checkboxes IDs and use that to show only those items that match the elements you checked. If no elements are checked, all items are shown (i.e. no filters are applied).
$("input[type='checkbox']").change(function()
{
var list = "";
$("input[type='checkbox']").each(function()
{
if(this.checked)
{
list = list + '.' + $(this).attr('id');
}
});
if(list !=='')
{
$("div.inditem").hide();
$(list).show();
}
else {
$("div.inditem").show();
}
});
I have been looking for a 'complete' solution to nesting parent child checkboxes that change state correctly based on a hierarchy.
Most 'solutions' do not work or only work to one level. They also require you to name the checkboxes in a particular way.
This Stack Overflow discussion covers the main points but also provide a good solution discovered by Rory here.
I have tested it within my development project and it works perfectly standalone. However, I am using Bootstrap 2.x and for checkboxes
I have a JSFiddle which shows the working example code, then my version with a disabled parent checkbox and then the bootsrap code version which does not work.
<!DOCTYPE html>
<body>
<!-- Raw working example from site http://css-tricks.com/indeterminate-checkboxes/ -->
<b>Raw working example</b>
<p>
<ul>
<li>
<input type="checkbox" name="tall" id="tall">
<label for="tall">Tall Things</label>
<ul>
<li>
<input type="checkbox" name="tall-1" id="tall-1">
<label for="tall-1">Buildings</label>
</li>
<li>
<input type="checkbox" name="tall-2" id="tall-2">
<label for="tall-2">Giants</label>
<ul>
<li>
<input type="checkbox" name="tall-2-1" id="tall-2-1">
<label for="tall-2-1">Andre</label>
</li>
<li>
<input type="checkbox" name="tall-2-2" id="tall-2-2">
<label for="tall-2-2">Paul Bunyan</label>
<ul>
<li>
<input type="checkbox" name="tall-2-2-1" id="tall-2-2-1">
<label for="tall-2-2-1">Son</label>
</li>
<li>
<input type="checkbox" name="tall-2-2-2" id="tall-2-2-2">
<label for="tall-2-2-2">Daughter</label>
</li>
</ul>
</li>
</ul>
</li>
<li>
<input type="checkbox" name="tall-3" id="tall-3">
<label for="tall-3">Two sandwiches</label>
</li>
</ul>
</li>
<li>
<input type="checkbox" name="short" id="short">
<label for="short">Short Things</label>
<ul>
<li>
<input type="checkbox" name="short-1" id="short-1">
<label for="short-1">Smurfs</label>
</li>
<li>
<input type="checkbox" name="short-2" id="short-2">
<label for="short-2">Mushrooms</label>
</li>
<li>
<input type="checkbox" name="short-3" id="short-3">
<label for="short-3">One Sandwich</label>
</li>
</ul>
</li>
</ul>
<hr>
<!-- Non Bootstrap Example -->
<b>My initial code example - Is Working</b>
<p>
<ul>
<li>
<input type="checkbox" name="" value="" disabled><strong>Ford</strong>
<ul>
<li>
<input type="checkbox" name="" value="">Fiesta</label>
</li>
<li>
<input type="checkbox" name="" value="">Focus</label>
</li>
<li>
<input type="checkbox" name="" value="">Mondeo</label>
</li>
</ul>
</li>
<li>
<input type="checkbox" name="" value="" disabled><strong>Vauxhall</strong>
<ul>
<li>
<input type="checkbox" name="" value="">Corsa</label>
</li>
<li>
<input type="checkbox" name="" value="">Astra</label>
</li>
<li>
<input type="checkbox" name="" value="">Vectra</label>
</li>
</ul>
</li>
</ul>
<hr>
<!-- Bootstrap Example -->
<b>Bootstrap based code example - Not Working</b>
<p>
<ul>
<li>
<label class="checkbox">
<input type="checkbox" name="" value="" disabled><strong>Ford</strong>
</label>
<ul>
<li>
<label class="checkbox">
<input type="checkbox" name="" value="">Fiesta</label>
</li>
<li>
<label class="checkbox">
<input type="checkbox" name="" value="">Focus</label>
</li>
<li>
<label class="checkbox">
<input type="checkbox" name="" value="">Mondeo</label>
</li>
</ul>
</li>
<li>
<label class="checkbox">
<input type="checkbox" name="" value="" disabled><strong>Vauxhall</strong>
</label>
<ul>
<li>
<label class="checkbox">
<input type="checkbox" name="" value="">Corsa</label>
</li>
<li>
<label class="checkbox">
<input type="checkbox" name="" value="">Astra</label>
</li>
<li>
<label class="checkbox">
<input type="checkbox" name="" value="">Vectra</label>
</li>
</ul>
</li>
</ul>
$(function () {
// Apparently click is better chan change? Cuz IE?
$('input[type="checkbox"]').change(function (e) {
var checked = $(this).prop("checked"),
container = $(this).parent(),
siblings = container.siblings();
container.find('input[type="checkbox"]').prop({
indeterminate: false,
checked: checked
});
function checkSiblings(el) {
var parent = el.parent().parent(),
all = true;
el.siblings().each(function () {
return all = ($(this).children('input[type="checkbox"]').prop("checked") === checked);
});
if (all && checked) {
parent.children('input[type="checkbox"]').prop({
indeterminate: false,
checked: checked
});
checkSiblings(parent);
} else if (all && !checked) {
parent.children('input[type="checkbox"]').prop("checked", checked);
parent.children('input[type="checkbox"]').prop("indeterminate", (parent.find('input[type="checkbox"]:checked').length > 0));
checkSiblings(parent);
} else {
el.parents("li").children('input[type="checkbox"]').prop({
indeterminate: true,
checked: false
});
}
}
checkSiblings(container);
});
});
My understanding is that the code needs to be changed somewhere to use parents or closest. Can someone who is a much better code please help identify where the change needs to happen to get the Bootstrap version working.
Take a look at the free JSTree user control. It is JavaScript-based, open source and allows to be configured for multiple styles of tree views, for example:
Since the checkboxes displayed here are just images, you can replace them by radio buttons easily, and via event handling you can disallow multiple selections so they behave like radio buttons if required.
This is achieved by specifying the "checkbox" plugin as follows (see the snippet I provided below for the complete working code):
$(function () {
$("#demo1")
.jstree({
"themes": {
"theme": "apple","dots": false,"icons": false
},
"plugins": ["themes", "html_data", "checkbox", "sort", "ui"]
});
});
The corresponding HTML structure looks like this, just include it in the body of your page:
<div id="demo1" class="demo" style="height:100px;">
<ul>
<li id="phtml_1"> Root node 1
<ul>
<li id="phtml_2"> Child node 1
</li>
<li id="phtml_3"> Child node 2
</li>
</ul>
</li>
<li id="phtml_4"> Root node 2
</li>
</ul>
</div>
To get the checked values, use this function (assuming you have created a div with id="listForDisplay" as I did in the JSFiddle example):
var $listForDisplay = $("#listForDisplay");
function displayList(data) { // see: https://www.jstree.com/docs/events/
var i, j, r = [];
for (i = 0, j = data.selected.length; i < j; i++) {
r.push(data.instance.get_node(data.selected[i]).text);
}
$listForDisplay.html('Selected: ' + r.join(', '));
}
This code can either be triggered in a click event or you can bind JSTree events like I did. Appending the following to the previous JavaScript snippet does the job:
$("#demo1")
.on('loaded.jstree', function (e, data) {
displayList(data);
})
.on('change_state.jstree', function (e, data) {
displayList(data);
});
Note: When a parent node is selected, the parent name is listed along with the childs. If only the childs are selected, the related parent(s) will not be listed.
You can find more about the options specifying the behaviour of this plugin here.
Runnable code snippet (complete code)
$(function() {
var $demo1 = $("#demo1");
var $listForDisplay = $("#listForDisplay");
function displayList(data) { // see: https://www.jstree.com/docs/events/
var i, j, r = [];
for (i = 0, j = data.selected.length; i < j; i++) {
r.push(data.instance.get_node(data.selected[i]).text);
}
$listForDisplay.html('Selected: ' + r.join(', '));
}
$demo1.jstree({
"themes": {
"theme": "apple",
"dots": false,
"icons": false
},
"plugins": ["themes", "html_data", "checkbox", "sort", "ui"]
});
$demo1.on('loaded.jstree', function(e, data) {
displayList(data);
});
$demo1.on('changed.jstree', function(e, data) {
displayList(data);
});
});
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/themes/default/style.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.2.1/jstree.min.js"></script>
</head>
<body>
<div id="demo1" class="demo" style="height:100px;">
<ul>
<li id="phtml_1"> Root node 1
<ul>
<li id="phtml_2"> Child node 1
</li>
<li id="phtml_3"> Child node 2
</li>
</ul>
</li>
<li id="phtml_4"> Root node 2
</li>
</ul>
</div>
<br/>
<div id="listForDisplay" />
</body>
you can try something like this
$(function () {
$('input[type="checkbox"]').change(function (e) {
var checked = $(this).prop("checked"),
container = $(this).closest("li"),//get closest li instead of parent
siblings = container.siblings();
container.find('input[type="checkbox"]').prop({
indeterminate: false,
checked: checked
});
function checkSiblings(el) {
var parent = el.parent().parent(),
all = true,
parentcheck=parent.children("label");//get the label that contains the disabled checkbox
el.siblings().each(function () {
return all = ($(this).find('input[type="checkbox"]').prop("checked") === checked);
});
//use parentcheck instead of parent to get the children checkbox
if (all && checked) {
parentcheck.children('input[type="checkbox"]').prop({
indeterminate: false,
checked: checked
});
checkSiblings(parent);
} else if (all && !checked) {
parentcheck.children('input[type="checkbox"]').prop("checked", checked);
parentcheck.children('input[type="checkbox"]').prop("indeterminate", (parent.find('input[type="checkbox"]:checked').length > 0));
checkSiblings(parent);
} else {
parentcheck.children('input[type="checkbox"]').prop({
indeterminate: true,
checked: false
});
}
}
checkSiblings(container);
});
});
http://jsfiddle.net/Mvs87/2/
I am developing a checkbox tree where i need three states of checkbox, I know there is two state of checkbox, but i have to use indeterminate
Check
Uncheck
Indeterminate
How can i developed these type of tree using javascript?
This is a trivial one from scratch: http://jsfiddle.net/pimvdb/MgYs7/1/.
var span = document.getElementById('span');
span.setAttribute('data-state', 0);
span.onselectstart = function() { return false }; // prevent selecting, doesn't look too good
span.onclick = function() {
var state = span.getAttribute('data-state') - 0; // convert to number
if(state === 0) { // set next symbol
span.innerHTML = 'V';
} else if(state === 1) {
span.innerHTML = 'X';
} else {
span.innerHTML = '';
}
span.setAttribute('data-state', (state + 1) % 3); // set state; 3 will be 0 again
};
<div id="page-wrap">
<h1>Indeterminate Checkboxes</h1>
<ul>
<li>
<input type="checkbox" name="tall" id="tall">
<label for="tall">Tall Things</label>
<ul>
<li>
<input type="checkbox" name="tall-1" id="tall-1">
<label for="tall-1">Buildings</label>
</li>
<li>
<input type="checkbox" name="tall-2" id="tall-2">
<label for="tall-2">Giants</label>
<ul>
<li>
<input type="checkbox" name="tall-2-1" id="tall-2-1">
<label for="tall-2-1">Andre</label>
</li>
<li>
<input type="checkbox" name="tall-2-2" id="tall-2-2">
<label for="tall-2-2">Paul Bunyan</label>
</li>
</ul>
</li>
<li>
<input type="checkbox" name="tall-3" id="tall-3">
<label for="tall-3">Two sandwiches</label>
</li>
</ul>
</li>
<li>
<input type="checkbox" name="short" id="short">
<label for="short">Short Things</label>
<ul>
<li>
<input type="checkbox" name="short-1" id="short-1">
<label for="short-1">Smurfs</label>
</li>
<li>
<input type="checkbox" name="short-2" id="short-2">
<label for="short-2">Mushrooms</label>
</li>
<li>
<input type="checkbox" name="short-3" id="short-3">
<label for="short-3">One Sandwich</label>
</li>
</ul>
</li>
</ul>
</div>
$(function() {
// Apparently click is better chan change? Cuz IE?
$('input[type="checkbox"]').change(function(e) {
var checked = $(this).prop("checked"),
container = $(this).parent(),
siblings = container.siblings();
container.find('input[type="checkbox"]').prop({
indeterminate: false,
checked: checked
});
function checkSiblings(el) {
var parent = el.parent().parent(),
all = true;
el.siblings().each(function() {
return all = ($(this).children('input[type="checkbox"]').prop("checked") === checked);
});
if (all && checked) {
parent.children('input[type="checkbox"]').prop({
indeterminate: false,
checked: checked
});
checkSiblings(parent);
} else if (all && !checked) {
parent.children('input[type="checkbox"]').prop("checked", checked);
parent.children('input[type="checkbox"]').prop("indeterminate", (parent.find('input[type="checkbox"]:checked').length > 0));
checkSiblings(parent);
} else {
el.parents("li").children('input[type="checkbox"]').prop({
indeterminate: true,
checked: false
});
}
}
checkSiblings(container);
});
});
You can use already developed plugins (or read their code if you are just curious how to manipulate the checkboxes' states).
Just drop one of them. If you choose niTree plugin I can help you with any questions concerning the code:
https://github.com/AlexLibs/niTree
I would use values -1, 0 and 1. Every onclick the attached function checks its value.
-1 = Indeterminate
0 = unchecked
1 = checked.
If 0 change to 1
If 1 change to -1
If -1 change to 0
If the value = -1 add this property (e.g. via jQuery) to the checkbox:
$(checkbox).prop("indeterminate", true);
For every other value the indeterminate value should be false.
See this link for example
Of course your tree logic should act on what its value is going to be e.g. unchecking children or setting parent at indeterminate.