I am creating hierarchy relations list with parent Childs and sub-childs if i checked parent then all Childs with checked but i clicked on Childs then sub-childs will be checked. everything is working fine but its work on second click not working on first click. here is my fiddle example. fiddle link here http://jsfiddle.net/fahadsheikh/qdkwy0s7/8/
function changeCategoryStatus(_this, id) {
var main = document.querySelector(".main-checkbox" id);
var children = document.querySelectorAll(".sub-checkbox" id);
function toggleCheck() {
var array=[];
children.forEach(child => {
if($(this).prop("checked") == true){
child.checked = child.checked = true
}
else if($(this).prop("checked") == false){
child.checked = child.checked = false
}
array.push(child.value);
})
return array;
}
if(main){
main.addEventListener("click", toggleCheck);
}
//for sub-parent category
var sub_parent = document.querySelector(".sub-parent" id);
var sub_children = document.querySelectorAll(".sub-checkbox" id);
function toggleCheck() {
var array=[];
sub_children.forEach(child => {
if($(this).prop("checked") == true){
child.checked = child.checked = true
}
else if($(this).prop("checked") == false){
child.checked = child.checked = false
}
array.push(child.value);
})
return array;
}
if(sub_parent){
sub_parent.addEventListener("click", toggleCheck);
}
var status = $(_this).prop('checked') == true ? 'active' : 'inactive';
$.ajax({
type: 'POST',
url:"{{url('admin/categories-status')}}",
data: {
id: id,
status: status,
_token: "{{ csrf_token() }}"
},
success: function (result) {
$("#status-success").show();
$("#status-success").html(result.success);
setTimeout(function() {
$("#status-success").hide()
}, 3000);
}
});
}
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#banner-message {
background: #fff;
border-radius: 4px;
padding: 20px;
font-size: 25px;
text-align: center;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
}
button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
}
#banner-message.alt {
background: #0084ff;
color: #fff;
margin-top: 40px;
width: 200px;
}
#banner-message.alt button {
background: #fff;
color: #000;
}
<div >
<div >
<li data-parent="4" data-position="4" data-newposition="1">second room
<span >
<label >
<input type="checkbox" id="user-4"
onclick="changeCategoryStatus(event.target, 4);"
>
<span ></span>
</label>
</span>
<div id="item-move" ><i aria-hidden="true"></i></div></li>
<ul >
<li data-parent="5" data-position="1" data-newposition="1">second-child room
<span >
<label >
<input type="checkbox" id="user-5"
onclick="changeCategoryStatus(event.target, 5);"
>
<span ></span>
</label>
</span>
<div ><i aria-hidden="true"></i></div></li>
<ul >
<li data-parent="6" data-position="1" data-newposition="0">second subchild
<span >
<label >
<input type="checkbox" id="user-6"
onclick="changeCategoryStatus(event.target, 6);"
>
<span ></span>
</label>
</span>
<div ><i aria-hidden="true"></i></div></li>
</ul>
</ul>
</div>
<div >
<li data-parent="7" data-position="4" data-newposition="2">third-room
<span >
<label >
<input type="checkbox" id="user-7"
onclick="changeCategoryStatus(event.target, 7);"
>
<span ></span>
</label>
</span>
<div id="item-move" ><i aria-hidden="true"></i></div></li>
<ul >
<li data-parent="9" data-position="1" data-newposition="1">third-child
<span >
<label >
<input type="checkbox" id="user-9"
onclick="changeCategoryStatus(event.target, 9);"
>
<span ></span>
</label>
</span>
<div ><i aria-hidden="true"></i></div></li>
<ul >
<li data-parent="10" data-position="1" data-newposition="0">third-subchild
<span >
<label >
<input type="checkbox" id="user-10"
onclick="changeCategoryStatus(event.target, 10);"
>
<span ></span>
</label>
</span>
<div ><i aria-hidden="true"></i></div></li>
</ul>
</ul>
</div>
</div>
thanks for help.
CodePudding user response:
The main issue with your current logic is that you are attaching the toggleCheck()
function to the main checkbox every time the checkbox is clicked. This causes the odd behaviour you see.
Also note that your HTML is invalid. li
elements must be children of the ul
only, not div
, and the ul
itself cannot be a child of another ul
. You need to structure your nested lists correctly. You can also improve the HTML by removing the incremental id and class attributes. They are an anti-pattern which leads to more complex code than necessary. Use DOM traversal to relate elements instead.
Regarding the JS code, you should avoid the use of the inline onclick
event handlers as they are no longer good practice. Use unobtrusive event handlers added via your JS logic. Also you're redefining the toggleCheck()
function numerous times, which is a big code smell.
With all that said, the HTML and JS can be massively simplified:
$('.sortable :checkbox').on('change', e => {
let $cb = $(e.target);
let isChecked = $cb.prop('checked');
$cb.closest('li').find(':checkbox').prop('checked', isChecked);
/*
// AJAX commented out for this demo only
$.ajax({
type: 'POST',
url: "{{url('admin/categories-status')}}",
data: {
id: $cb.prop('id'),
status: isChecked ? 'active' : 'inactive',
_token: "{{ csrf_token() }}"
},
success: function(result) {
$("#status-success").html(result.success).show();
setTimeout(function() {
$("#status-success").hide();
}, 3000);
}
});
*/
});
body {
/* background-color: #20262E; */
padding: 20px;
font-family: Helvetica;
}
.move {
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg p" crossorigin="anonymous"/>
<div >
<ul >
<li data-parent="4" data-position="4" data-newposition="1">
second room
<span >
<label >
<input type="checkbox" id="4" />
<span ></span>
</label>
</span>
<div >
<i aria-hidden="true"></i>
</div>
<ul >
<li data-parent="5" data-position="1" data-newposition="1">
second-child room
<span >
<label >
<input type="checkbox" id="5" />
<span ></span>
</label>
</span>
<div >
<i aria-hidden="true"></i>
</div>
<ul >
<li data-parent="6" data-position="1" data-newposition="0">
second subchild
<span >
<label >
<input type="checkbox" id="6" />
<span ></span>
</label>
</span>
<div ><i aria-hidden="true"></i></div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul >
<li data-parent="7" data-position="4" data-newposition="2">
third-room
<span >
<label >
<input type="checkbox" id="7" />
<span ></span>
</label>
</span>
<div >
<i aria-hidden="true"></i>
</div>
<ul >
<li data-parent="9" data-position="1" data-newposition="1">
third-child
<span >
<label >
<input type="checkbox" id="9" />
<span ></span>
</label>
</span>
<div >
<i aria-hidden="true"></i>
</div>
<ul >
<li data-parent="10" data-position="1" data-newposition="0">
third-subchild
<span >
<label >
<input type="checkbox" id="10" />
<span ></span>
</label>
</span>
<div >
<i aria-hidden="true"></i>
</div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>