开发者

Cascading dropdownlist with mvc and jQuery not working

I am trying to use a solution for a cascading dropdownlist (the selection in one dropdownlist determines the options in the second one) found here:

http://www.pieterg.com/post/2010/04/12/Cascading-DropDownList-with-ASPNET-MVC-and-JQuery.aspx

<script src="../../Scripts/jquery-1.4.1.js" type="text/javascript"></script>
    <script src="../../Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            //Hook onto the MakeID list's onchange event
            $("#CustomerId").change(function () {
                //build the request url
                var url = "Timesheet/Tasks";
                //fire off the request, passing it the id which is the MakeID's selected item value
                $.getJSON(url, { id: $("#CustomerId").val() }, function (data) {
                    //Clear the Model list
                    $("#TaskId").empty();
                    //Foreach Model in the list, add a model option from the data returned
                    $.each(data, function (index, optionData) {
                        $("#TaskId").append("<option value='" + optionData.ID + "'>" + optionData.Description + "</option>");
                    });
                });
            }).change();
        });
    </script>
    <h2>
        Index</h2>
    <fieldset>
        <legend>Fields</legend>
        <div>
            <label for="Customers">
                Kund:</label>
            <%:Html.DropDownListFor(m => m.Customers, new SelectList(Model.Customers,"Id", "Name"), new {@id="CustomerId"}) %>
            <%--<%:Html.DropDownListFor(m => m.CustomerId, new SelectList(Model.Customers,"Id", "Name")) %>--%>
            &nbsp;&nbsp;
            <label for="Tasks">
                Aktiviteter:</label>
            <%:Html.DropDownListFor(m => m.Tasks, new SelectList(Model.Tasks,"Id", "Name"), new {@id="TaskId"}) %>
            <%--<%:Html.DropDownListFor(m => m.TaskId, new SelectList(Model.Tasks,"Id", "Name")) %>--%>
<%--            <select id="TaskId" name="TaskId">
            </select>--%>
        </div>
    </fieldset>

And here's the Action method that gets the tasks:

    public JsonResult Tasks(string id)
    {
        var result = new JsonResult();
        //var tasks = from t in _model.Tasks
        //            where t.CustomerId.ToString() == id
        //            select t;
        List<Task> tasklist = new List<Task>();
        foreach (var task in _model.Tasks)
        {
            if(task.CustomerId.ToString() == id)
                tasklist.Add(task);
        }

        //result.Data = tasks.ToList();
        result.Data = tasklist;

        result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
        return result;
    }

I have two problems:

  1. The second dropdownlist does not change at all depending on the first one. I have tried all kinds of variants (as you can see from the commented out dropdownlists). I do get an error message in Firebug, but I can't interpret it (see below).
  2. The linq expression in the Action method doesn't seem to work for some reason, which is really strange, because I've been using this sort of expression a lot without problems before. Maybe I'm tired and missing something, but I can't see it. The expression returns all tasks, not just the ones with the same id as the current customer. The foreach works fine, which makes it even more strange... This is completely unrelated to the first problem, because again, the foreach works fine and only selects three tasks (which is correct). But still the second dropdownlist shows all tasks...

Any help appreciated!

Firebug error log:

<html>
    <head>
        <title>A circular reference was detected while serializing an object of type 'Tidrapportering.Models.Task'.</title>
        <style>
         body {font-family:"Verdana";font-weight:normal;font-size: .7em;color:black;} 
         p {font-family:"Verdana";font-weight:normal;color:black;margin-top: -5px}
         b {font-family:"Verdana";font-weight:bold;color:black;margin-top: -5px}
         H1 { font-family:"Verdana";font-weight:normal;font-size:18pt;color:red }
         H2 { font-family:"Verdana";font-weight:normal;font-size:14pt;color:maroon }
         pre {font-family:"Lucida Console";font-size: .9em}
         .marker {font-weight: bold; color: black;text-decoration: none;}
         .version {color: gray;}
         .error {margin-bottom: 10px;}
         .expandable { text-decoration:underline; font-weight:bold; color:navy; cursor:hand; }
        </style>
    </head>

    <body bgcolor="white">

            <span><H1>Server Error in '/' Application.<hr width=100% size=1 color=silver></H1>

            <h2> <i>A circular reference was detected while serializing an object of type 'Tidrapportering.Models.Task'.</i> </h2></span>

            <font face="Arial, Helvetica, Geneva, SunSans-Regular, sans-serif ">

            <b> Description: </b>An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

            <br><br>

            <b> Exception Details: </b>System.InvalidOperationException: A circular reference was detected while serializing an object of type 'Tidrapportering.Models.Task'.<br><br>

            <b>Source Error:</b> <br><br>

            <table width=100% bgcolor="#ffffcc">
               <tr>
                  <td>
                      <code>

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.</code>

                  </td>
               </tr>
            </table>

            <br>

            <b>Stack Trace:</b> <br><br>

            <table width=100% bgcolor="#ffffcc">
               <tr>
                  <td>
                      <code><pre>

[InvalidOperationException: A circular reference was detected while serializing an object of type &#39;Tidrapportering.Models.Task&#39;.]
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +1478
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +194
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeEnumerable(IEnumerable enumerable, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +126
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +1311
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +194
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeCustomObject(Object o, StringBuild开发者_StackOverflow社区er sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +502
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +1355
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +194
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeCustomObject(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +502
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +1355
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +194
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeEnumerable(IEnumerable enumerable, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +126
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeValueInternal(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +1311
   System.Web.Script.Serialization.JavaScriptSerializer.SerializeValue(Object o, StringBuilder sb, Int32 depth, Hashtable objectsInUse, SerializationFormat serializationFormat) +194
   System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj, StringBuilder output, SerializationFormat serializationFormat) +26
   System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj, SerializationFormat serializationFormat) +74
   System.Web.Script.Serialization.JavaScriptSerializer.Serialize(Object obj) +6
   System.Web.Mvc.JsonResult.ExecuteResult(ControllerContext context) +458
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) +39
   System.Web.Mvc.&lt;&gt;c__DisplayClass14.&lt;InvokeActionResultWithFilters&gt;b__11() +60
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) +391
   System.Web.Mvc.&lt;&gt;c__DisplayClass16.&lt;InvokeActionResultWithFilters&gt;b__13() +61
   System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) +285
   System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +830
   System.Web.Mvc.Controller.ExecuteCore() +136
   System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +111
   System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +39
   System.Web.Mvc.&lt;&gt;c__DisplayClass8.&lt;BeginProcessRequest&gt;b__4() +65
   System.Web.Mvc.Async.&lt;&gt;c__DisplayClass1.&lt;MakeVoidDelegate&gt;b__0() +44
   System.Web.Mvc.Async.&lt;&gt;c__DisplayClass8`1.&lt;BeginSynchronous&gt;b__7(IAsyncResult _) +42

   System.Web.Mvc.Async.WrappedAsyncResult`1.End() +141
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +54
   System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +40
   System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +52
   System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38
   System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8841105

   System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean&amp; completedSynchronously) +184
</pre></code>

                  </td>
               </tr>
            </table>

            <br>

            <hr width=100% size=1 color=silver>

            <b>Version Information:</b>&nbsp;Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1

            </font>

    </body>
</html>

UPDATE:

I now updated it to the following:

Action method for getting tasks associated with the selected customer:

    public JsonResult Tasks(string id)
    {
        var result = new JsonResult();
        var tasks =
            _model.Tasks.Where(task => task.CustomerId.ToString() == id).Select(
                task => new {ID = task.Id, Name = task.Name});
        result.Data = tasks;

        result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
        return result;
    }

And in the View:

    <div>
        <label for="Customers">
            Kund:</label>
        <%:Html.DropDownListFor(m => m.Customers, new SelectList(Model.Customers,"Id", "Name"), new {@id="CustomerId"}) %>
        &nbsp;&nbsp;
        <label for="Tasks">
            Aktiviteter:</label>
        <%:Html.DropDownListFor(m => m.Tasks, new SelectList(Model.Tasks,"Id", "Name"), new {@id="TaskId"}) %>
    </div>

Now I get results somehow filtered and selected in the second dropdown, the number of options are correct when selecting different customers. However, the value in the task dropdownlist is "undefined" for all of them...

UPDATE 2:

I found the problem:

In the jQuery I had forgotten to fix the property names of the task objects. Here's the working version:

    $(document).ready(function () {
        //Hook onto the MakeID list's onchange event
        $("#CustomerId").change(function () {
            //build the request url
            var url = "Timesheet/Tasks";
            //fire off the request, passing it the id which is the MakeID's selected item value
            $.getJSON(url, { id: $("#CustomerId").val() }, function (data) {
                //Clear the Model list
                $("#TaskId").empty();
                //Foreach Model in the list, add a model option from the data returned
                $.each(data, function (index, optionData) {
                    $("#TaskId").append("<option value='" + optionData.Id + "'>" + optionData.Name + "</option>");
                });
            });
        }).change();
    });

But I would like to know how to get a default value for the dropdownlists. Since otherwise the customer dropdownlist will have a value when you first get to the page, but the task list won't...


JsonResult uses JavascriptSerializer to generate JSON data, and JavascriptSerializer does not support circular references. Maybe the following post will help you solve your problem: Json and Circular Reference Exception

Update

Instead of working around the circular reference, just return a List of another object, with just the two fields you need: ID and Description. It would look something like this:

var tasklist = _model.Tasks.Where(x => x.CustomerId.ToString() == id)
                           .Select(x => new { ID = task.ID, Description = task.Description });
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜