treeview with checkboxes, 2 or more treeviews: another solution

1 posts, 0 answers
  1. Greg
    Greg avatar
    19 posts
    Member since:
    Jun 2012

    Posted 20 Nov 2012 Link to this post

    I have posted previously showing how to load the treeview one layer at a time in this post(my post)

    treeview and checkboxes: a Solution

    This is another solution that loads all items and allows MORE than 1 treeview on a HTML form and separates out the different check boxes lists when you post back the form. I have 3 treeviews on the one HTML Form
    As with the first post you need to have the latest version( refer to that post).
    I am basing this on the ASP.NET MVC example on this site:

    My html looks like this:
    int cnt = -1;
                    .Items(treeview =>
                        bool expandParent = true;
                        treeview.Add().Text("Annual Sales").Id("-1")
                            .Items(item =>
                                foreach (AnnualSalesRange annualSalesRange in Model.SearchSaveModel.FilteredAnnualSalesRangeList)
                                    //String annualSalesText = @String.Format("{0} ({1})", Model.FilteredAnnualSalesRangeList[cnt].AnnualSalesRangeName, Model.FilteredAnnualSalesRangeList[cnt].AnnualSalesRangeCount);
                                    String annualSalesText = Model.SearchSaveModel.FilteredAnnualSalesRangeList[cnt].AnnualSalesRangeName;
    The treeview control has logic placed in it to parse the list of annaulSalesRanges. I am using a int: cnt variable to get the different list items on each iteration.
    There are 2 other things worth note:
    1. this line: treeview.Add().Text("Annual Sales").Id("-1")
    2  the last line           @Html.Hidden("LastYearSalesCheckedStates");
    for the first line there is a -1 as the Id. I will use this in a Javascript to hide the top most checkbox in the tree. In Kendo there isn't a Checkable function as there was in Telerik. (see second last part of javascript)
    The hidden field will hold the checked and unchecked states. I will populate this with javascript and use it in the post back Controller method.

    The java script looks like this:
    <script type="text/javascript">   
        function LastYearSalesCheckedState() {
            this.AnnualSalesRangeID = '';
            this.IsChecked = false;
        var LastYearSalesCheckedStates = [];
        $(document).ready(function () {
            $("#LastYearSalesTreeView input:checkbox[name=checkedNodes]").on('click', function () {           
                    var rangeID = $(this).attr('value');
                    // find the corresponding rangeID in the array
                    var rangeIDs = $.grep(LastYearSalesCheckedStates, function (n, i) {
                        return n.AnnualSalesRangeID == rangeID;
                    if (rangeIDs.length > 0) {
                        var LastYearSalesChecked = rangeIDs[0];
                        if ($(this).is(':checked')) {
                            LastYearSalesChecked.IsChecked = true;
                        } else {
                            LastYearSalesChecked.IsChecked = false;
                    else {
                        var LastYearSalesChecked = new LastYearSalesCheckedState();
                        LastYearSalesChecked.AnnualSalesRangeID = $(this).attr('value');
                        if ($(this).is(':checked')) {
                            LastYearSalesChecked.IsChecked = true;
                        } else {
                            LastYearSalesChecked.IsChecked = false;
                var jsonData = JSON.stringify(LastYearSalesCheckedStates);
            $("#LastYearSalesTreeView input:checkbox[name=checkedNodes]").each(function () {
                if ($(this).attr('value') < 0) {
                    //hide the check box, mimics checkable(false)
            //populate the array with checked items
            $("#LastYearSalesTreeView input:checked[name=checkedNodes]").each(function () {
                var LastYearSalesChecked = new LastYearSalesCheckedState();
                LastYearSalesChecked.AnnualSalesRangeID = $(this).attr('value');
                if ($(this).is(':checked')) {
                    LastYearSalesChecked.IsChecked = true;
                } else {
                    LastYearSalesChecked.IsChecked = false;
    The first thing to note is the javascript object: LastYearSalesCheckedState, this holds one checkbox id and check state.
    The javascript array: LastYearSalesCheckedStates holds an array of LastYearSalesCheckedState.
    They are populated:
    1. When the checkbox is clicked
    2. When the view is initially rendered, if there are any checked Checkboxes being sent from Controller(see last part of javascript)

    The LastYearSalesCheckedStates  array is JSON stringified and assigned to the hidden field.
    There is a separate submit button for each treeview, which posts the whole form. It changes the form's action prior to posting so that a different action on the controller can manage each of the treeviews

    Here is an abridged version of my controller Action

    //public ActionResult FilteredLastYearSales(SearchModel model, List<TreeViewItem> LastYearSalesTreeView_checkedNodes)
    // public ActionResult FilteredLastYearSales(SearchModel model, int[] checkedNodes)
            public ActionResult FilteredLastYearSales(SearchModel model)
                List<LastYearSalesCheckedState> LastYearSalesCheckedStateList = null;
                if (Request.Form["LastYearSalesCheckedStates"] != null)
                    LastYearSalesCheckedStateList = CommonTools.DeSerializeJsonObject<List<LastYearSalesCheckedState>>(Request.Form["LastYearSalesCheckedStates"]);
    The first commented out signature is the old telerik signature, where the [name of the control]_checkNodes was the array holding the checked items.
    The second commented out signature is the new Kendo signature where checkNodes holds ALL checked and only checked items. It doesn't seperate the 2 or more treeviews as did the telerik treeviews. It puts them all checked checkbos together regardless of which control  they belong to. So it is only good when there is 1 treeview being posted back.
    And that is the reason for having the JSON stringify array for each treeview control being posted back in separate hidden fields. It is in Request.Form["LastYearSalesCheckedStates"]
    The LastYearSalesCheckedState class must be the same structure as the javascript object: LastYearSalesCheckedState
    public class LastYearSalesCheckedState
            public String AnnualSalesRangeID { get; set; }
            public bool IsChecked { get; set; }
    The generic CommonTools.DeSerializeJsonObject method is a helper that de-serializes the Json string into a LastYearSalesCheckedState  List:

    using System.Web.Script.Serialization;
     public static T DeSerializeJsonObject<T>(String strJSON) where T : class
                JavaScriptSerializer ser = new JavaScriptSerializer();
                return ser.Deserialize<T>(strJSON) as T;
    I hope this is clear to follow
    If not post  question


Back to Top