skip to Main Content

I’m currently deveoling an asp.net core web app with html and javascript.
The problem is that I’m trying to implement a treeview where each element is a checkbox, and when I click an element I want the child elements to be also selected.
You can see an example below:
Example

And here is the code:

@using ProvaFormularis.Assets.TVItems;

@model IEnumerable<MeasurementModel>

@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>


<style>
    /* Remove default bullets */
    ul, #myUL {
        list-style-type: none;
    }

    /* Remove margins and padding from the parent ul */
    #myUL {
        margin: 0;
        padding: 0;
        overflow-y: scroll;
        height: 450px;
        background: #f9f9f9;
    }

    /* Style the caret/arrow */
    .caret {
        cursor: pointer;
        user-select: none; /* Prevent text selection */
        font-size: large;
    }

        /* Create the caret/arrow with a unicode, and style it */
        .caret::before {
            content: "25B6";
            color: black;
            display: inline-block;
            margin-right: 6px;
            font-size: large;
        }

    /* Rotate the caret/arrow icon when clicked on (using JavaScript) */
    .caret-down::before {
        transform: rotate(90deg);
    }

    /* Hide the nested list */
    .nested {
        display: none;
    }

    /* Show the nested list when the user clicks on the caret/arrow (with JavaScript) */
    .active {
        display: block;
    }

    li {
        padding: 12px;
    }

    label {
        font-size: large
    }

    input[type=checkbox] {
        transform: scale(1.5);
    }
</style>


<form>
    <ul>
        @foreach (TVStandard tvstandard in StaticClass.TVList.StandardsList)
        {
            <li>
                <span class="caret"></span>
                <input type="checkbox" class="checker" [email protected] name="Standard" [email protected] unchecked>
                <label [email protected]>@tvstandard.Name (@tvstandard.folderName)</label>
                <ul class="nested">
                    @foreach(TVSection tvsection in tvstandard.Children)
                    {
                        <li>
                            <span class="caret"></span>
                            <input type="checkbox" class="checker" [email protected] name="Section" [email protected] unchecked>
                            <label [email protected]>@tvsection.Name (@tvsection.scriptName)</label>
                            <ul class="nested">
                                @foreach (TVMode tvmode in tvsection.Children) 
                                {
                                    <li>
                                        <span class="caret"></span>
                                        <input type="checkbox" class="checker" [email protected] name="Mode" [email protected] unchecked>
                                        <label [email protected]>@tvmode.Name</label>
                                        <ul class="nested">
                                            @foreach (TVFreq tvfreq in tvmode.Children) 
                                            {
                                                <li>
                                                    <input type="checkbox" class="checker" [email protected] name="Frequency" [email protected] unchecked>
                                                    <label [email protected]>@tvfreq.Name (@tvfreq.ID)</label>
                                                </li>
                                            }
                                        </ul>
                                    </li>
                                }
                            </ul>
                        </li>
                    }
                </ul>
            </li>
        }
    </ul>
</form>

<script>
    var toggler = document.getElementsByClassName("caret");
    var i;

    for (i = 0; i < toggler.length; i++) {
        toggler[i].addEventListener("click", function () {
            this.parentElement.querySelector(".nested").classList.toggle("active");
            this.classList.toggle("caret-down");
        });
    }
</script>

<script>
    var toggler = document.getElementsByClassName("checker");
    var i;
    for (i = 0; i < toggler.length; i++) {
        toggler[i].addEventListener("click", function () {
            var lis = this.parentElement.getElementsByClassName(".nested").children;
            var j;
            for (j = 0; j < lis.length) {
                var toggler2 = lis.getElementsByClassName("checker");
                var k;
                for (k = 0; k < toggler2.length; k++) { 

                    toggler2[k].click();
                }
            }
        });
    }
</script>

So, does anybody know how to correctly implement this behavior?

Please note that the first script is the one that deplows the child elements and the second one is the one that must select the childs elements and does not work.


PD: I’ve tested the correct retrieval of click event and the click action of the checkboxes and it works fine. I’ve done that with these scripts:

<script>
    var toggler = document.querySelectorAll("input[type=checkbox]");
    var i;
    for (i = 0; i < toggler.length; i++) {
        toggler[i].click();
    }
</script>
<script>
    var toggler = document.querySelectorAll("input[type=checkbox]");
    var i;
    for (i = 0; i < toggler.length; i++) {
        toggler[i].addEventListener("click", function () {
            this.checked = true;
        });
    }
</script>

2

Answers


  1. In your second script, you have a syntax error in the for loop. It should be for (j = 0; j < lis.length; j++) instead of for (j = 0; j < lis.length).

    Instead of using .getElementsByClassName(), you should use .querySelectorAll() to select elements by class name.

    When you use lis.getElementsByClassName("checker"), it will return an HTMLCollection, so you’ll need to iterate through it.

    var toggler = document.getElementsByClassName("checker");
    var i;
    
    for (i = 0; i < toggler.length; i++) {
        toggler[i].addEventListener("click", function () {
            var lis = this.parentElement.querySelector(".nested").children;
            var j;
    
            for (j = 0; j < lis.length; j++) {
                var toggler2 = lis[j].querySelectorAll(".checker");
                var k;
    
                for (k = 0; k < toggler2.length; k++) {
                    toggler2[k].checked = this.checked;
                }
            }
        });
    }
    
    Login or Signup to reply.
  2. If you are capable of achieving this task using jQuery, it will significantly simplify the process for you. Your objective is to dynamically assign an attribute to each parent checkbox with a specific ID, such as ‘data-parent-$id,’ and simultaneously assign that parent’s ID as a class to its child elements. By implementing this approach, you will have the capability to create an unlimited hierarchical structure of parent-child trees, each with checkboxes. For a practical demonstration, please refer to the following code example.

    $(document).ready(function() {
                // Attach a change event to all checkboxes in the tree
                $('.checkbox-tree :checkbox').change(function() {
                    var isChecked = $(this).prop('checked');
                    var $parent_id = $(this).data('parent');
                    selectChildren($parent_id, isChecked);
                    
                });
    
                // Function to select all children checkboxes
                function selectChildren($parent_id, isChecked) {
                    $('.checkbox-tree').find('.child_of_'+$parent_id).not(this).prop('checked', isChecked);
                    $('.checkbox-tree').find('.child_of_'+$parent_id).trigger('change');
                }
    
            });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Checkboxes</title>
        </head>
        <body>
            <div class="checkbox-tree">
                <label><input type="checkbox" value="1" data-parent="1"> Parent 1</label>
                <ul>
                    <li><label><input type="checkbox" class="child_of_1" data-parent="2" value="2"> Child 1.1</label></li>
                    <li><label><input type="checkbox" class="child_of_1" data-parent="3" value="3"> Child 1.2</label></li>
    
                    <ul>
                        <li><label><input type="checkbox" class="child_of_3" value="2"> Child 1.1</label></li>
                        <li><label><input type="checkbox" class="child_of_3" value="3"> Child 1.2</label></li>
                    </ul>
                </ul>
            </div>    
        </body>
    </html>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search