I wanted to have a checkbox tree form and I used dynatree jquery tree to do that.
Then I found out dynatree doesn't use real checkboxes so I placed html checkbox inside the tree.
Its working fine until I realise when the node is expanded/collapsed it remvoe the checked (the tick) value
Is there a way in javascript I can write a function to prevent this happening?
Thanks so much. Here is my code
$(function(){
$("#tree").dynatree({
// using default options
checkbox: false,
selectMode: 3,
noLink: true,
});
<div id="tree">
<ul>
<li id="key1" title="Look, a tool tip!">
<input type="checkbox" id="chb-key1" name="selected_items" value="Item 1" class="" />Item 1</li>
<li id="key2">
<input type="checkbox" id="chb-key2" name="selected_items" value="Item 2" />Item 2</li>
<li id="key3">
<input type="checkbox" id="chb-key3" name="selected_items" value="Item 3" />Folder with some children
<ul>
<li id="key31">
<input type="checkbox" id="chb-key31" name="selected_items" value="Item 3.1" />Sub-item 3.1</li>
<li id="key32" class="selected">
<input type="checkbox" id="chb-key32" name="selected_items" value="Item 3.2" />Sub-item 3.2
<ul>
<li id="key321" class="selected">
<input type="checkbox" id="chb-key321" name="selected_items" value="Item 3.2.1" />Sub-item 3.2.1</li>
<li id="key322" class="selected">
<input type="checkbox" id="chb-key322" name="selected_items" value="Item 3.2.2" />Sub-item 3.2.2</li>
</ul>
</li>
</ul>
</li>
I came across the same problem. The way I solved it was to put "checkbox: true," and hide your real checkboxes and check/uncheck them each time the fake boxes are checked/unchecked.
Here is my code:
$("#storyCategories").dynatree({
//Tree parameters
persist: false,
checkbox: true,
selectMode: 3,
activeVisible: true,
//Un/check real checkboxes recursively after selection
onSelect: function (select, dtnode) {
if (select) {
$("#chb-" + dtnode.data.key).attr("checked", "checked").addClass("hidden");
} else {
$("#chb-" + dtnode.data.key).removeAttr("checked").addClass("hidden");
}
// $("#chb-" + dtnode.data.key).attr("checked", select).addClass("hidden");
dtnode.visit(function (dtnode) {
if (select) {
$("#chb-" + dtnode.data.key).attr("checked", "checked").addClass("hidden");
} else {
$("#chb-" + dtnode.data.key).removeAttr("checked").addClass("hidden");
}
}, null, true);
},
//Hack to prevent appearing of checkbox when node is expanded/collapsed
onExpand: function (select, dtnode) {
$("#storyCategories :checkbox").addClass("hidden");
//$("#chb-" + dtnode.data.key).attr("checked", dtnode.isSelected()).addClass("hidden");
if (dtnode.isSelected()) {
$("#chb-" + dtnode.data.key).attr("checked", "checked").addClass("hidden");
} else {
$("#chb-" + dtnode.data.key).removeAttr("checked").addClass("hidden");
}
}
});
//Hide real checkboxes
$("#storyCategories :checkbox").addClass("hidden");
I used code from this article but had to update it: http://www.llakomy.com/articles/adding-dynatree-with-checkboxes-to-a-form.
Related
Basically, I have multiple UL's with a class "list". Each of them has multiple radio buttons. I would like to do something with span element upon the last radio option of individual UL's being checked. And undo it after another radio button of that same UL is being checked.
The code essentially works but it is triggering for all of the UL's instead of the one in which the click occurred.
I used alert (which is commented out) to check if I'm getting everything with 'each' and it seems to work fine.
$(document).ready(function() {
$('ul.list').each(function() {
//alert($(this).text());
$("ul.list input[type$='radio']").click(function() {
if ($("li:last-of-type input[type$='radio']").prop("checked")) {
// do something with span
} else {
// do something with span
}
});
});
});
<ul class="list">
<li><input type="radio">Option 1</input>
</li>
<li><input type="radio">Option 2</input>
</li>
<li><input type="radio">Bonus</input><span>Bonus text</span></li>
</ul>
<ul class="list">
<li><input type="radio">Option 1</input>
</li>
<li><input type="radio">Option 2</input>
</li>
<li><input type="radio">Bonus</input><span>Bonus text</span></li>
</ul>
Actually you don't need the loop in this case just attach the click directly to the selector :
$(document).ready(function() {
$("ul.list :radio").click(function() {
if ( $(this).prop("checked") )
{
// do something with span
} else {
// do something with span
}
});
});
NOTE 1 : The input are self-closing tags so thsy should be like :
<input type="radio"/>Option 1
Instead of :
<input type="radio">Option 1</input>
NOTE 2 : Use this keyword to target the clicked element instead :
if( $(this).prop("checked") ){
Hope this helps.
$(document).ready(function() {
$("ul.list :radio").change(function() {
if ( !$(this).is(':last-child') && $(this).is(":checked") )
{
$(this).closest("ul").find('span').show();
}else{
$(this).closest("ul").find('span').hide();
}
});
});
ul.list li>span{
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list">
<li><input type="radio" name="same_name_1" checked/>Option 1</li>
<li><input type="radio" name="same_name_1" />Option 2</li>
<li><input type="radio" name="same_name_1" />Bonus<br><span>Bonus text</span></li>
</ul>
<ul class="list">
<li><input type="radio" name="same_name_2" checked/>Option 1</li>
<li><input type="radio" name="same_name_2" />Option 2</li>
<li><input type="radio" name="same_name_2" />Bonus<br><span>Bonus text</span></li>
</ul>
I have here 2 ul list which contains inside two lists of items and 2 delete buttons. I use here only one button click function for both delete buttons and I would like to have something like: when the user checks the items in the List 1 then only the items in the List 1 will be deleted after pressing the delete button no matter items in List 2 are checked or not and vice versa. Because now I can use the delete button in List 1 to delete items in List 2. What I have read on the internet is after pressing the delete button I might use something call: $(event.currentTarget).parent() to get the exact content list belongs to this button and then process inside of this list. Am I right?
$(document).ready(function() {
$("#delete").click(function() {
var deleteItem = [];
$("input:checkbox").each(function() {
var $this = $(this);
if ($this.is(":checked")) {
deleteItem.push($this.attr("name"));
}
});
if (deleteItem != []) {
if (deleteItem.indexOf("cbox1") > -1 && deleteItem.indexOf("cbox2") > -1) {
$("#box1").remove();
$("#box2").remove();
}
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul>List 1
<li id="box1"><span><input type="checkbox" name="cbox1" value="1" />Visit W3Schools1.com!</span></li>
<li id="box2"><span><input type="checkbox" name="cbox2" value="2" />Visit W3Schools2.com!</span></li>
<li id="box3"><span><input type="checkbox" name="cbox3" value="3" />Visit W3Schools3.com!</span></li>
<button id="delete">Delete</button>
</ul>
<ul>List 2
<li id="box1"><span><input type="checkbox" name="cbox1" value="1" />Visit W3Schools1.com!</span></li>
<li id="box2"><span><input type="checkbox" name="cbox2" value="2" />Visit W3Schools2.com!</span></li>
<li id="box3"><span><input type="checkbox" name="cbox3" value="3" />Visit W3Schools3.com!</span></li>
<button id="delete">Delete</button>
</ul>
As I mentioned in my comment, you should use a class instead of id's because id's must be unique.
Here is a Fiddle Demo.
JQUERY:
$('.delete').click(function() {
var items = $(this).parent('ul').find('input:checked');
items.closest('li').remove();
});
When an element with the class 'delete' is clicked, it finds the parent ul and then looks for checked inputs. Once those are found, it looks for the closest li for those inputs and removes them.
HTML:
<ul>List 1
<li class="box1"><span><input type="checkbox" name="cbox1" value="1" />Visit W3Schools1.com!</span></li>
<li class="box2"><span><input type="checkbox" name="cbox2" value="2" />Visit W3Schools2.com!</span></li>
<li class="box3"><span><input type="checkbox" name="cbox3" value="3" />Visit W3Schools3.com!</span></li>
<button class="delete">Delete</button>
</ul>
<ul>List 2
<li class="box1"><span><input type="checkbox" name="cbox1" value="1" />Visit W3Schools1.com!</span></li>
<li class="box2"><span><input type="checkbox" name="cbox2" value="2" />Visit W3Schools2.com!</span></li>
<li class="box3"><span><input type="checkbox" name="cbox3" value="3" />Visit W3Schools3.com!</span></li>
<button class="delete">Delete</button>
</ul>
OP asked how to find the name of the checked inputs. Here is one way to do it:
$('.delete').click(function() {
var items = $(this).parent('ul').find('input:checked');
//iterate over objects and log the name
$.each(items, function( index, value ) {
console.log($(this).attr('name'));
});
items.closest('li').remove();
});
I've added an iterator which will go through the objects in items and output the name attribute to the console (F12 in most browsers). Here is an updated Fiddle Demo.
Note :Id must be unique. If you are tending to use same Id convert that to a class
Working Demo
$(document).ready(function() {
$(".delete").click(function() {
var deleteItem = [];
$("input:checkbox").each(function() {
var $this = $(this);
if ($this.is(":checked")) {
$(this).parent().parent().remove()
}
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul>List 1
<li id="box1"><span><input type="checkbox" name="cbox1" value="1" />Visit W3Schools1.com!</span>
</li>
<li id="box2"><span><input type="checkbox" name="cbox2" value="2" />Visit W3Schools2.com!</span>
</li>
<li id="box3"><span><input type="checkbox" name="cbox3" value="3" />Visit W3Schools3.com!</span>
</li>
<button class="delete">Delete</button>
</ul>
<ul>List 2
<li id="box1"><span><input type="checkbox" name="cbox1" value="1" />Visit W3Schools1.com!</span>
</li>
<li id="box2"><span><input type="checkbox" name="cbox2" value="2" />Visit W3Schools2.com!</span>
</li>
<li id="box3"><span><input type="checkbox" name="cbox3" value="3" />Visit W3Schools3.com!</span>
</li>
<button class="delete">Delete</button>
</ul>
Yeah you are right in the use of .parent() jquery method. If i understand what you trie to do, you can maybe improve your code in this way :
$(document).ready(function() {
$("#delete").click(function() {
var parentUl = $(this).parent(); // get the parent url of the clicked button
var li_items = parentUl.find('li'); // get the li in the parent ul
li_items.each(function() { // for each li retrieved
if ($(this).children('input:checkbox').is(':checked')) // if the input is checked
$(this).remove(); // we remove it
});
});
Hope it helps ! :)
EDIT :
As other says, you should use a class instead of an id. per definition, an id should be considers as an unique block identifier in your html. in your case, you have 2 buttons so it's better to do this : <button class="delete"></button>
My code works fine in case I check the main check box all the child check boxes get selected too but when I click the child first the parent check box does not get checked.
Here is my asp.net webforms code
<table id="dtPage" class="table table-striped table-hover ">
<thead>
<tr>
<th><asp:CheckBox ID="chkActiveUsers" runat="server" ClientIDMode="Static" />Associate</th>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:CheckBox ID="chkUserStatus" CssClass="enable-user" runat="server" />
</td>
</tr>
and here is my JavaScript:
$(document).ready(function () {
$('#chkActiveUsers').click(function () {
$(".enable-user input[type='checkbox']").prop('checked', $(this).is(':checked'));
});
});
My Question is: How can I make it work vice versa i.e. when child is check parent should get checked too and when no child is checked parent should get unchecked too
You can simply write an event handler for your child checkboxes and compare the length of checked and total existing checkboxes like this:-
$('input[name$="chkUserStatus"]').click(function () {
if ($('input[name$="chkUserStatus"]').length == $('input[name$="chkUserStatus"]:checked').length)
$('#chkActiveUsers').prop('checked', true);
else
$('#chkActiveUsers').prop('checked', false);
});
Update:
If you want that if only the last child checkbox is unchecked only then the paremt should be unchecked then you can do it like this:-
$('input[name$="chkUserStatus"]').click(function () {
if ($('input[name$="chkUserStatus"]:checked').length != 0)
$('#chkActiveUsers').prop('checked', true);
else
$('#chkActiveUsers').prop('checked', false);
});
You need to have some way of grouping the children and parents so you can find the parent checkbox relative to the child checkbox. Once you've achieved that you can just do checks against the checkboxes to see if you need to do anything.
$(document).on('click', 'input.child', function() {
var parent = $(this).closest('.typeContainer').find('input.parent'),
parentChecked = parent.is(':checked');
if ($(this).is(':checked') && !parentChecked) { // If the child is checked but the parent is not
parent.prop('checked', true);
} else if (!$(this).is(':checked') && parentChecked) { // Else if the child is not checked and the parent is
var doUncheck = true;
$(this).closest('ul').find('input.child').not(this).each(function() { // Loop through all the sibling children checkboxes
if ($(this).is(':checked')) { // If one of them is checked
doUncheck = false; // Don't uncheck the parent
return; // Exit loop because required parameters are complete
}
});
if (doUncheck) {
parent.prop('checked', false);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="typeContainer">
<li>
<input type="checkbox" class="parent" />Parent 1
</li>
<li>
<ul>
<li>
<input type="checkbox" class="child" />Child 1.1
</li>
<li>
<input type="checkbox" class="child" />Child 1.2
</li>
<li>
<input type="checkbox" class="child" />Child 1.3
</li>
<li>
<input type="checkbox" class="child" />Child 1.4
</li>
</ul>
</li>
</ul>
<ul class="typeContainer">
<li>
<input type="checkbox" class="parent" />Parent 2
</li>
<li>
<ul>
<li>
<input type="checkbox" class="child" />Child 2.1
</li>
<li>
<input type="checkbox" class="child" />Child 2.2
</li>
<li>
<input type="checkbox" class="child" />Child 2.3
</li>
<li>
<input type="checkbox" class="child" />Child 2.4
</li>
</ul>
</li>
</ul>
Posted a question on about the same project in the morning. After battling it for a while came up with a bit different approach.
Trying to build a filter. And the idea is that a filter checkboxes have matching id's with filtered items classes. So, once a filter item clicked, filtration is applied to item class. Classes (except for inditem) and ids are dynamic
simplified html of it
<div class="itemswrap">
<div class="inditem dynamic1"></div>
<div class="inditem dynamic2"></div>
<div class="inditem dynamic3"></div>
<div class="inditem dynamic2"></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>
js
$(".lifilter").each(function() {
var filter1 = $(this).find('.filtercheck').attr('id');
if ( $(this).find('.filtercheck').attr('checked') ) {
$(this).find('.filtercheck').click(function(){
$('.' + filter1).removeClass('checkeditem').hide();
});
}
else
{
$(this).find('.filtercheck').click(function(){
$('.inditem').hide();
$('.' + filter1).addClass('checkeditem');
});
}
});
and this one marked as important not to be hidden when extra items are added into filtration
.checkeditem {display:block !important}
Initial filtration works fine. But when I click on checked item the associated div does not hide.
Do you mean something like
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();
}
});
.checkeditem {
display: block !important
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="itemswrap">
<div class="inditem dynamic1">dynamic1</div>
<div class="inditem dynamic2">dynamic2</div>
<div class="inditem dynamic3">dynamic3</div>
<div class="inditem dynamic2">dynamic2</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>
The problem with the code is that the event handler attaches the second click event on the first successful case. This means that the "click" on the checkbox is being given the "addclass" case, and all subsequent clicks are being handled by that handler instead of the intended one.
Using the same HTML. I created this:
$(document).ready(function() {
$(".filtercheck").click(function(){
$('.inditem').hide();
var filter1 = $(this).attr('id');
$('.' + filter1).toggleClass('checkeditem');
});
});
which I think is the intended behavior? Instead of individually attaching click handlers, I simply attached a single handler to all of them. It would be fairly easy to do something like
$(this).prop()
to determine if the currently clicked on item had was active or not. For this simple example, I opted to just use a class toggle to illustrate the point.
I have a script that will check and uncheck all children checkboxes in a nested list. I am now trying to get it so I can check a low level checkbox and it will check all the parents only back up to the highest level. Here is a JSFiddle
<ul class="tree" id="tree">
<li><input type="checkbox" name="account_settings" value="yes">Account Settings <!-- AND SHOULD CHECK HERE -->
<ul>
<li><input type="checkbox" name="one" value="one">AS One</li>
<li><input type="checkbox" name="two" value="two">AS Two</li>
<li><input type="checkbox" name="user_roles" value="user_roles">Users & Roles <!-- SHOULD CHECK HERE -->
<ul>
<li><input type="checkbox" name="user_role" value="add">Add</li>
<li><input type="checkbox" name="user_role" value="delete">Delete</li> <!-- CHECK HERE -->
</ul>
</li>
</ul>
</li>
<li><input type="checkbox" name="rl_module" value="yes">RL Module</li>
<li><input type="checkbox" name="rl_module" value="yes">Accounting
<ul>
<li><input type="checkbox" name="vat" value="yes">VAT</li>
<li><input type="checkbox" name="bank_account" value="yes">Banking
<ul>
<li><input type="checkbox" name="view" value="yes">View</li>
<li><input type="checkbox" name="crud" value="yes">CRUD</li>
</ul>
</li>
</ul>
</li>
</ul>
And the corresponding javascript:
$('input[type=checkbox]').click(function(){
// if is checked
if($(this).is(':checked')){
// check all children
$(this).parent().find('li input[type=checkbox]').prop('checked', true);
// check all parents
$(this).parent().prev().prop('checked', true);
} else {
// uncheck all children
$(this).parent().find('li input[type=checkbox]').prop('checked', false);
}
});
It looks like you want something like this
$('input[type=checkbox]').click(function(){
if(this.checked){ // if checked - check all parent checkboxes
$(this).parents('li').children('input[type=checkbox]').prop('checked',true);
}
// children checkboxes depend on current checkbox
$(this).parent().find('input[type=checkbox]').prop('checked',this.checked);
});
FIDDLE
If you want to check up and down hierarchy - you can do it like this
$('input[type=checkbox]').click(function(){
// children checkboxes depend on current checkbox
$(this).next().find('input[type=checkbox]').prop('checked',this.checked);
// go up the hierarchy - and check/uncheck depending on number of children checked/unchecked
$(this).parents('ul').prev('input[type=checkbox]').prop('checked',function(){
return $(this).next().find(':checked').length;
});
});
FIDDLE
This should do it:
$('input[type=checkbox]').click(function () {
$(this).parent().find('li input[type=checkbox]').prop('checked', $(this).is(':checked'));
var sibs = false;
$(this).closest('ul').children('li').each(function () {
if($('input[type=checkbox]', this).is(':checked')) sibs=true;
})
$(this).parents('ul').prev().prop('checked', sibs);
});
jsFiddle example
Latest update handles up and down the hierarchy, and siblings.
Just use jquery.parents(). It is somewhat similar to find() except it searches all parents. Something like this might be close to what you are looking for:
$(this).parents('li').each(function() {
$(this).children('input').prop('checked', true);
});
See http://api.jquery.com/parents/ for more information.
EDIT: Alright, here is a solution that works:
http://jsfiddle.net/3y3Pb/12/
EDIT2: And a more streamlined solution here:
http://jsfiddle.net/3y3Pb/14/
Have a JSFiddle: http://jsfiddle.net/3y3Pb/16/
I would recommend adding a parent attribute to the checkboxes. This parent attribute will reference the parent checkbox's id so that you don't have to worry about your structure changing:
$('input type=[checkbox]').change(function () {
$('#' + $(this).attr('parent')).prop('checked', this.checked);
});
Ex:
<input type="checkbox" name="account_settings" value="yes" id="as">Account Settings
<ul>
<li><input type="checkbox" name="one" value="one" parent="as" id="one">AS One</li>
You can use prevAll() also
I have the same issue. In my case there are multiple checkboxes in li with labels, and each checkbox above target have class parent (generated in js)
$(this).parents().prevAll('input:checkbox.parent').each(function () {
$(this).attr('checked', true);
});