Thursday, August 20, 2009

ASP.NET MVC with jQuery DynaTree plugin for Checkboxes

I've just added the jQuery DynaTree plugin to an ASP.NET MVC project that I'm working on and I thought that I'd do a quick write-up on how I did that using an example page.

Here are the Actions from the Controller:

public ActionResult DynaTree()
{
    return View("DynaTree", (object)"1,2,3,4");
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult DynaTree(FormCollection collection)
{
    string selectedItems = Request.Form["SelectedItems"];
    string[] items = selectedItems.Split(',');
    return View("DynaTree", (object)selectedItems);
}

The first Action, the GET verb, simple returns the view with a comma separated list of items that we want pre-selected. Interestingly if the second parameter is a string then the overload of the View() function maps that parameter to a master file so you have to cast it to an object to let it know that you're passing in the Model in this param. I could have also set that string in the ViewData collection.

The POST Action pulls the list out of the <input> tag named SelectedItems.

Here are the contents of the <asp:Content> tag in the view:

<% using(Html.BeginForm()) { %>
    <div id="tree">
        <ul>
            <li id="1">First upper item</li>
            <li id="2">Second upper item</li>
            <li id="3">Third upper item
                <ul>
                    <li id="4">First Lower item in Third layer</li>
                    <li id="5">Second Lower item in Third layer</li>
                </ul>
            </li>
            <li id="6">Fourth upper item
                <ul>
                    <li id="7">First Lower item in Fourth layer</li>
                    <li id="8">Second Lower item in Fourth layer</li>
                </ul>
            </li>
            <li id="9">Fifth upper item</li>
        </ul>
    </div>
    <% =Html.Hidden("SelectedItems", Model) %>
    <input type="button" name="submit" value="Submit" />
<% } %>

<!-- Also needed are references to the jQuery library. This is in the Site.master file -->

<script src="/Scripts/jquery.dynatree.min.js" type="text/javascript"></script>
<script src="/Scripts/TestDynaTree.js" type="text/javascript"></script>

There's nothing special in here.

The JavaScript that I used with this:

$(document).ready(function() {

    $("#tree").dynatree({
        onSelect: function(flag, dtnode) {
            // This will happen each time a check box is selected/deselected
            var selectedNodes = dtnode.tree.getSelectedNodes();
            var selectedKeys = $.map(selectedNodes, function(node) {
                return node.data.key;
            });
            // Set the hidden input field's value to the selected items
            $('#SelectedItems').val(selectedKeys.join(","));
        },
        checkbox: true
    });

    // Remove all of the icons from the tree
    $('#tree .ui-dynatree-icon').remove();

    // Split out the items listed in the SelectedItems hidden input box
    var items = $('#SelectedItems').val().split(',');
    var tree = $("#tree").dynatree("getTree");
    // Mark each of those items as selected in the tree
    for (var i = 0; i < items.length; i++) {
        var node = tree.getNodeByKey(items[i]);
        node.select(true);
        node.activate();
    }
});

The node.activate() function will expand the parent node for any child node that you select.

5 comments:

  1. Guy,
    I just have to say thanks for your Javascript eval engine trick for C#, on "StackOverflow.com". All of the other JScript avenues didn't work under VS2008, but yours does. Thanks - You're a lifesaver.
    Dirk
    Re: "For anybody developing in C# on Silverlight here's a pretty neat trick that I've just discovered that allows evaluation of an expression by calling out to the Javascript engine:
    double result = (double) HtmlPage.Window.Eval("15 + 35");"
    ------------------------------------------------------------------
    (Note - I didn't see where else I could post this thanks, so I submitted as a comment to one of your other posts)

    ReplyDelete
  2. I am talking with reference to this example wwwendt.de/.../samples.html Is there any way I can prevent unselecting when any child node is clicked

    ReplyDelete
  3. So if a child node is selected then you want the parent to always be selected right?
    Yes, I believe that's possible. I don't have any sample code to hand at the moment to test it with but when the select event is fired you can make sure that all the parents, grandparents of the node are checked or you can check them during that event. Also, when the event is fired you can check to see if any children are selected and if so prevent a box from being unchecked.

    ReplyDelete
  4. I could not get the view to work correctly... I had to cast "Model" as an object to remove the error I received. When I ran the site, I did not get a checklist tree... only an unordered list. Any idea what I'm missing?

    ReplyDelete
  5. @chris sounds like you're not declaring the object type that the view is using. Are you doing this in asp.net web forms or MVC. If the latter, which view engine are you using, forms or razor?
    Basically at the top of the view (in MVC) you need to declare the object type for the Model so that the view knows what data type it's dealing with. In MVC this will be different depending on the view type you're using: Forms, Razor or other...

    ReplyDelete