views:

2340

answers:

2

I have a web page on which I would like to display dynamically a tree based on a JSON array with the help of jQuery. Each node of my tree has a checkbox associated to it. When I click a node which has children, I would like all of them to be checked. I’ve already taken care of printing the tree and the checkboxes and I am now trying to select children nodes and I am not able.

Below is the code (simplified) that I have so far. Does anybody has an idea how I could automatically check the children checkboxes when a checkbox is checked with jQuery?

Thanks!

<html>
<head>

    <script type="text/javascript" src="jquery-1.3.2.min.js"></script>

    <script type="text/javascript">

        var myJSON = {
            "d": {
             "__type": "Branch", 
             "Name": "$", 
             "FullPath": "$\\$", 
             "SubBranch": [
              {
               "__type": "Branch", 
               "Name": "System", 
               "FullPath": "$\\System", 
               "SubBranch": [
                {
                 "__type": "Branch", 
                 "Name": "Library", 
                 "FullPath": "$\\System\\Library", 
                 "SubBranch": [
                 ]
                }, 
                {
                 "__type": "Branch", 
                 "Name": "Configuration", 
                 "FullPath": "$\\System\\Configuration", 
                 "SubBranch": [
                  {
                   "__type": "Branch", 
                   "Name": "Reimage", 
                   "FullPath": "$\\System\\Configuration\\Reimage", 
                   "SubBranch": [
                   ]
                  }, 
                  {
                   "__type": "Branch", 
                   "Name": "Installation", 
                   "FullPath": "$\\System\\Configuration\\Installation", 
                   "SubBranch": [
                   ]
                  }
                 ]
                }, 
               ]
              }
             ]
            }
        }

        var output;
        var indentationLevel = 0;

        function GetSpacing(numberOfSpaces) {
            var tabs = '';
            for (i = 0; i < numberOfSpaces; i++) {
                tabs += '&nbsp;&nbsp;&nbsp;';
            }
            return tabs;
        }

        function GetHtmlForFeaturePath(featurePath) {
            return '<div>' + GetSpacing(indentationLevel) + '<input type="checkbox" id="' + featurePath.FullPath + '" class="featureTreeCheckbox" />' + featurePath.Name + "</div>";
        }

        function GetHtmlForFeaturePaths(node) {
            output += GetHtmlForFeaturePath(node);

            indentationLevel++;

            jQuery.each(node.SubBranch, function() {
                GetHtmlForFeaturePaths(this);
            });

            indentationLevel--;
        }


        String.prototype.startsWith = function(str) {
            return this.match("^" + str) == str;
        }


        window.onload = function() {
            GetHtmlForFeaturePaths(myJSON.d);
            document.writeln(output);

      /* How do I tell a node to check its children? */
            $('input').click(function(event) {
                var clickedControlId = this.id;
                alert(clickedControlId);  

       /* alert($.grep(myJSON.d, function (a) { return a.FullPath == clickedControlId })); */
            });
        }

    </script>

</head>
<body>
    <a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;
</body>
</html>
+2  A: 

It is not a good practice to distinguish levels with spaces. Instead you should use a class or an id. This helps both the appearance (you can use css) and your code, since it defines logical levels.

Edit your code to produce a DOM like that:

<div class="level1">
<input id="$\$" class="featureTreeCheckbox" type="checkbox">$
    <div class="level2">
    <input id="$\System" class="featureTreeCheckbox" type="checkbox">System
        <div class="level3">
            <input id="$\System\Library" class="featureTreeCheckbox" type="checkbox">Library
        </div>
        <div class="level3">
            <input id="$\System\Configuration" class="featureTreeCheckbox" type="checkbox">Configuration
                <div class="level4">
                    <input id="$\System\Configuration\Reimage" class="featureTreeCheckbox" type="checkbox">Reimage<br/>
                    <input id="$\System\Configuration\Installation" class="featureTreeCheckbox" type="checkbox">Installation
                </div>
        </div>
    </div>
</div>

Each "levelx" class defines a level. You can easily style it like this:

<style>
.level1 { margin-left: 0px; }
.level2 { margin-left: 10px; }
.level3 { margin-left: 20px; }
.level4 { margin-left: 30px; }
</style>

Then you can use code like this:

<script type="text/javascript">

$(function() {
$('div.level1 input').change(function(event) {
    if ($(this).is(":checked")) {
        $(this).parent().find("input").attr("checked", "checked");
    }
});
$('div.level2 input').change(function(event) {
    if ($(this).is(":checked")) {
        $(this).parent().find(".level3 input").attr("checked", "checked");
        $(this).parent().find(".level4 input").attr("checked", "checked");
    }
});

$('div.level3 input').change(function(event) {
    if ($(this).is(":checked")) {
        $(this).parent().find(".level4 input").attr("checked", "checked");
    }
});

});
</script>
kgiannakakis
+2  A: 

I'd simplify what kgiannakakis did:

$(function() {
  $('div input:first').change(function(event) {
    if ($(this).is(":checked")) {
        $(this).next("div").find("input").attr("checked", "checked");
    } else {
        $(this).next("div").find("input").removeAttr("checked");
    }
  });
});

This should work for any number of levels.

Seb