0

Please help. I'm using MVC, razor 3, jquery. I dynamically create a multi select box when a dropdown selection changes. I bind the multiple selection to a List in my model. And it works, except it passes me the list of selected indice, instead of a list of the selected text. I want selected text, not index of the list. I set the value as text, but I have no luck.

if I manually create the list, everything works. How do I pass a list of selected options back to the controller?

I have this div in my view:

    <div class="row-fluid" id="divAvailableAssemblies"  hidden ="hidden">
    <label class="span4">Available Assemblies:</label>
    <select multiple="multiple" class="span8 ui-corner-all" id="Request_SelectingAssemblies" name="Request.SelectingAssemblies">
        @*<option value="test">test</option>
        <option value="test2">test2</option>*@

    </select>

</div>

Here my jquery:

<script type="text/javascript">
$(function () {
    $('#ddPartsToCreate').live('change',function () {
        var selectedPart = this.value;
        if (selectedPart < 6 || $("#txtOrderNumber").val()=="")
        {
            $("#divAvailableAssemblies").attr("hidden", "hidden");
            return;
        }

        $("#divAvailableAssemblies").removeAttr("hidden");

        $.ajax({
            type: 'POST',
            url: '@Url.Action("GetSelectingAssembliesFromOrder", "Home")',
            data: JSON.stringify({ orderNumber: $("#txtOrderNumber").val() }),
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            cache: false,
            async: false,
            success: function (response) {
                var returnedData = JSON.parse(response);

                var selectingAssemblies = $("#Request_SelectingAssemblies");

                selectingAssemblies.empty();

                for (var assembly in returnedData)
                {
                    //selectingAssemblies.append($('<option >', { value: assembly }).text(returnedData[assembly].Text)).hide().show();
                    //selectingAssemblies.append($('<option value=' + assembly + '>' + returnedData[assembly].Text + '</option>'));
                    //selectingAssemblies.append($('<option >', { value: assembly, text: returnedData[assembly].Text }));
                    //selectingAssemblies.append($('<option></option>').val(assembly).html(returnedData[assembly].Text));
                    //$("#Request_SelectingAssemblies").append($('<option>', { value: assembly }).text(returnedData[assembly].Text));

                    //$("#Request_SelectingAssemblies").append($('<option>', { value: assembly }).text(returnedData[assembly].Text));
                    //$('<option />', { value: assembly, text: returnedData[assembly].Text }).appendTo(selectingAssemblies);
                    selectingAssemblies.append($('<option></option>').val(assembly).html(returnedData[assembly].Text));


                }

            },
            error: function (jqXHR, textStatus, errorThrown) {
                alert(errorThrown);
            }
        });
    });

});

in the backend, I generate JSON:

            foreach (var assembly in pr.ShipParts)
        {
            sb.Append(String.Format(",{{\"Text\":\"{0}\", \"Value\":\"{1}\"}}", assembly.Mark.ToString(), assembly.Mark.ToString()));
            availableAssemblies.Add(assembly.Mark.ToString());

        }

I bind the multiple selection(Request_SelectingAssemblies) with this property in my model:

      public List<String> SelectingAssemblies
  {
      get
      {

          return _SelectingAssemblies;
      }
      set
      {
          _SelectingAssemblies = value;
      }
  }
  private List<String> _SelectingAssemblies = new List<string>();

When it gets to my action in the controller, SelectingAssemblies has index instead of the actual text. But I set the value of each option as text. If I set the option manually, they will show in source page and return the text. But since I dynamically create the options, they don't show in source page. I don't know how I can make MVC understand dynamic data. In the picture, the list of CX001, RBX001, RBX002 is dynamically created. if I hit F12 in IE, I will see them created correctly in the DOM. If I choose CX001 and RBX002, SelectionAssembies will have 0 and 2.

enter image description here Thanks

MsBugKiller
  • 813
  • 1
  • 7
  • 12
  • my other dropbox:
    @Html.DropDownListFor(x => x.Request.PartsToCreate, Model.GetPartsToCreate(), new { @class = "span8 ui-corner-all", id="ddPartsToCreate"})
    – MsBugKiller Jun 16 '15 at 17:42
  • What are you using to populate the dropdowns? You could look them up by id when you get the data into the controller if its done in the back end. – moikey Jun 16 '15 at 17:49
  • I get the list from some XML passed in to me, based on some condition. I can keep the list around somehow and look up the selected items later, but it's inefficient to do so because it's a long list and I only need a few the selected items. – MsBugKiller Jun 16 '15 at 20:08
  • What is the actual html generated for each option after you make an ajax call? –  Jun 17 '15 at 01:30
  • this is the actual html generated if I view source page: you noticed there is no options. But if I hit F12 and look at the DOM, they are there. I read some other posts. They said dynamically created html will not show in source page. – MsBugKiller Jun 17 '15 at 15:06
  • if I uncomment out the test options (test and test2) and pick one of them, it will be passed to the controller. But I only get the index for options that are dynamically created. – MsBugKiller Jun 17 '15 at 15:12
  • @MsBugKiller, Then in your `for (var assembly in returnedData)` loop, add a `console.log(assembly);` statement to check what it returns. Your controller method for generating the Json to return is not complete (suggest you show the full method), but its the strangest looking code I've seen for returning data to populate a dropdown –  Jun 18 '15 at 03:10
  • @StephenMuecke, I did, assembly give me correct text. As you can see in the C# code, I set both Text and Value to be the same text. I did that because I know MVC looks at the value in option. – MsBugKiller Jun 18 '15 at 16:45
  • Your server method should be just `var assemblies = pr.ShipParts.Select(x => x.Mark);return Json(assemblies, JsonRequestBehavior.AllowGet);` and in the ajax callback - `success: function (response) { $.each(response, function(index, item) { selectingAssemblies.append($('').text(item)); });` Note if the options value and text are the same, you only need to set the text (if an option does not have a `value` attribute it will post back its text value). –  Jun 18 '15 at 23:55
  • @StephenMuecke, I tried your code, it didn't work, but modified it a little bit and it works. I will post the working code. Thank you very much. – MsBugKiller Jun 19 '15 at 21:28
  • @MsBugKiller, Sorry but is just nonsense to build a json string an the server and then parse it back again on the client, not to mention duplicating the same value twice. Your writing more than twice as much code as necessary and sending 4 times as much data across the wire as necessary - just send an array of the values! –  Jun 19 '15 at 22:47
  • @StephenMuecke, I got the data from the back end. I have to conditionally build the list from the data in the database. I didn't put all of the code there. – MsBugKiller Jun 22 '15 at 15:04

1 Answers1

0

This is the latest and working code, thanks to @StephenMuecke:

<script type="text/javascript">
$(function () {
        $('#ddPartsToCreate').live('change',function () {
        var selectedPart = this.value;
        if (selectedPart < 6 || $("#txtOrderNumber").val()=="")
        {
            $("#divAvailableAssemblies").attr("hidden", "hidden");
            return;
        }

        $("#divAvailableAssemblies").removeAttr("hidden");

        $.ajax({
            type: 'POST',
            url: '@Url.Action("GetSelectingAssembliesFromOrder", "Home")',
            data: JSON.stringify({ orderNumber: $("#txtOrderNumber").val() }),
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            cache: false,
            async: false,
            success: function (response) {
                var returnedData = JSON.parse(response);
                var selectingAssemblies = $("#Request_SelectingAssemblies");
                $.each(returnedData, function (index, item) {
                    selectingAssemblies.append($('<option></option>').val(item.Value).html(item.Text));
                });

            },
            error: function (jqXHR, textStatus, errorThrown) {
                alert(errorThrown);
            }
        });
    });


});

    public ActionResult GetSelectingAssembliesFromOrder(String orderNumber)
    {
        return Json(model.GetSelectingAssembliesFromOrder(orderNumber), JsonRequestBehavior.AllowGet);
    }



    public String GetSelectingAssembliesFromOrder(String orderNumber)
    {
       //...
        StringBuilder sb = new StringBuilder();
        sb.Append("[");
        foreach (var assembly in pr.ShipParts)
        {
            string assemblyName = assembly.Mark.Trim();
            sb.Append(String.Format(",{{\"Text\":\"{0}\", \"Value\":\"{1}\"}}", assemblyName, assemblyName));//JSON to build the list
            //...
        }

        sb.Append("]");
        sb.Remove(1, 1);//remove extra comma
        _db.SaveChanges();
        return sb.ToString();
    }
MsBugKiller
  • 813
  • 1
  • 7
  • 12