ShaneKm
ShaneKm

Reputation: 21328

jquery tree traversal

I have a task where I need to traverse a tree (checking/un-checking individual items). I've written the code and it works correctly but slow at times. Please help me improve it.

Here is how it is suppose to work:

  1. Un-checking the parent unchecks all children of that parent
  2. Un-checking the (one or more) child nodes un-checks the parent
  3. Checking the parent automatically checks all it's children
  4. When all children are checked the parent gets checked as well automatically
    • this should also work with any depth tree..so if there are 3 level deep nodes unchecking the most inner child will uncheck the First parent of each node.

Few other considerations: Css classes:

So:

I hope this illustration will help: enter image description here

And part of HTML source code:

<ul class='treeList2b'><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:30px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Aparatura elektryczna, elektroenergetyka   </span></div>

<ul class='treeList2b'><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:60px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Silniki, napędy, automatyka napęd&#243;w </span></div>
<ul class='treeList2b'><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:90px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Silniki i napędy przemysłowe </span></div>
<ul class='treeList2b'><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Prądu stałego   </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Prądu przemiennego </span></div>
<ul class='treeList2b'><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:150px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>synchroniczne   </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:150px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>asynchroniczne </span></div>

</li></ul></li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Silniki krokowe   </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Siłowniki elektryczne   </span></div>
<ul class='treeList2b'><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:150px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Liniowe </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:150px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Obrotowe </span></div>
</li></ul></li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Serwosilniki, serwonapędy </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Inne </span></div>

</li></ul></li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:90px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Układy zabezpieczeń silnik&#243;w   </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:90px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Elektroniczne układy sterowania napęd&#243;w   </span></div>
<ul class='treeList2b'><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Przemienniki prądu stałego   </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Przemienniki częstotliwości (falowniki)   </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Układy łagodnego rozruchu (softstarty)   </span></div>

</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Sterowniki silnik&#243;w DC </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:120px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Sterowniki silnik&#243;w krokowych </span></div>
<ul class='treeList2b'><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:150px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Jednoosiowe   </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:150px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Wieloosiowe   </span></div>
</li><li class='open'>                        <div class="tlWrap clearfix marked checked" style="padding-left:150px;"><input type="checkbox" checked="checked" class="checkbox" name="SelectedBranch" id="SelectedBranch"><span>Wieloosiowe z interpolacją   </span></div>

</li></ul></li>

...

And my script:

<script type="text/javascript">
/*<![CDATA[*/
    $(function(){           
        $('ul.treeList2b .checkbox').click(function(e){
            e.stopPropagation();
            var obj = $(this).closest('li').find(':checkbox'); 
            obj.attr('checked', this.checked);
            var childCnt=obj.size();  // get childrent count - when parent was clicked
            var checkedCnt=obj.filter(':checked').length; // out of those get those that are checked
            if (childCnt==checkedCnt){
                obj.parents('li').each(function (index, element) {
                    var objSub = $(element).find('li');
                    childCnt = objSub.size();
                    checkedCnt = objSub.find(':checkbox:checked').length;
                    if (childCnt==checkedCnt) { 
                        $(element).find(':checkbox:first').attr("checked", true);
                        $(element).children('div.tlWrap').addClass('checked');
                    }
                    $(element).children('div.tlWrap').addClass('marked');
                });
            }else{ 
                var objParent = obj.parents('li').find(':checkbox:first');
                objParent.attr("checked", false);
                objParent.parent('div.tlWrap').removeClass('checked');
            }
            refleshCheckbox(this);
        });
    });
    function refleshCheckbox(obj){
        if(!$(obj).attr('checked')){
            $(obj).closest('li').find('div.tlWrap').removeClass('marked');
        } 
        if ($(obj).closest('ul').find(':checkbox:checked').length==0){
            $(obj).closest('ul').parent().find('div.tlWrap').removeClass('marked');
        }
    }
/*]]>*/
</script>

Upvotes: 1

Views: 1226

Answers (1)

mekwall
mekwall

Reputation: 28974

I won't be adding all the functionality to this answer since you'll learn more by implementing them yourself. But I made a test case on jsFiddle that works as illustrated:

$(".option-tree > li > label > input:checkbox").each(function(){
    var $this = $(this),
        options = $this.closest("li").find("> ul > li > label > input:checkbox");

    $this.change(function(){
        options.prop("checked", $this[0].checked);
    });

    options.change(function(){
        var  all = options.length,
           checked = options.filter(":checked").length;
        $this[0].checked = all === checked;
    });

});

Note that the above example is using jQuery 1.6 where you have to use .prop instead of .attr and .removeAttr.

For earlier versions of jQuery (pre 1.6) it would look like this:

$(".option-tree > li > label > input:checkbox").each(function(){
    var $this = $(this),
        options = $this.closest("li").find("> ul > li > label > input:checkbox");

    $this.change(function(){
        if ($this[0].checked) {
            options.attr("checked", "checked");
        } else {
            options.removeAttr("checked");
        }
    });

    options.change(function(){
        var  all = options.length,
           checked = options.filter(":checked").length;
        $this[0].checked = all === checked;
    });

});

Upvotes: 2

Related Questions