Nay
Nay

Reputation: 97

ASP.NET MVC 5 Creating multiple DropDownLists from a single source on the client side

I am wondering if there is a way to create multiple DropDownLists on the client side from one source in the model.

The background is I need to create a view that contains about 30 DropDownLists. The DropDownLists are identical to one another, and each contains about 400 entries. My model contains one

List<SelectListItem> StandardProductTypes

to hold all entries for each DropDownList.

Here is what is in my current view:

@for (int i = 0; i < Model.Mappings.Count; i++)
{
    @Html.DropDownListFor(model => model.Mappings[i].SelectedStandardProductTypeKey,
                        new SelectList(Model.StandardProductTypes, "Value", "Text", Model.Mappings[i].SelectedStandardProductTypeKey))
}

As you can see, this is returning 30 x 400 = 12000 entries from the sever, and the page loads rather slowly.

All that is really required is only 400 entries transferred and they are replicated 30 times on the client side in the browser. Is there a way to achieve that? Any reference to reading materials or tutorials will be good.

Thanks in advance.

Nay

Upvotes: 0

Views: 1200

Answers (2)

James S
James S

Reputation: 3588

Ok firstly you have no need to create a new SelectList for every DropDownList as the source. The DropDownListFor method just requires an IEnumerable<SelectListItem> as a source, which you already have (and the selected value is determined by the property value it is for normally, so you don't need to pass this in explicitly for the selected value.

Ie given "StandardProductTypes" is already IEnumerable<SelectListItem> you can simplify your DropDownListFor from

 @Html.DropDownListFor(model => model.Mappings[i].SelectedStandardProductTypeKey,
                        new SelectList(Model.StandardProductTypes, "Value", "Text", Model.Mappings[i].SelectedStandardProductTypeKey))

To

 @Html.DropDownListFor(model => model.Mappings[i].SelectedStandardProductTypeKey,
                        Model.StandardProductTypes)

Also I would generally NOT put stuff like a List<SelectListItem> in the model, because you don't need to pass it back after postback. Having it in the Viewbag is fine.

However that's just good practice, and besides the point, as the HTML here will still include all the options for all the dropdowns. TO solve your issue you want to return it only once, and then use some client side jQuery/javascript to replicate it

EG:

use

@Html.DropDownListFor(model => model.Mappings[i].SelectedStandardProductTypeKey, new List<SelectListItem>())
@Html.Hidden(String.Format("Mappings[{0}].SelectedStandardProductTypeKey_Initial",i), Model.Mappings[i].SelectedStandardProductTypeKey) 

in place of the dropdown (so you have the correct initial value)

Then a bit of script at the end to fill the dropdownlists:

<script>
var ddlVals= new Array();
@foreach(var item in Model.StandardProductTypes) // get all the select list items into a javascript array
{
   @Html.Raw(String.Format("ddlVals.push(['{0}','{1}']);", item.Key, item.Value))
}

$('input[type="select"][name$="SelectedStandardProductTypeKey"]').each(function()
{
   var initValue $("name='" + $(this).attr("name") + "_Initial'").val();
   foreach(var item in ddlVals)
   {
     var html = '<option value="' + item[0] + '"'
     if (item[0] == initValue){ html = html + ' selected="selected"'} 
     html = html + '>' + item[1] + '</option>';
     $(this).append(html);
   }
}

</script>

EDIT

May be quicker using the idea in Edi G's answer

But you'd still need to select the correct initial value.

So keep the hidden fields and dropdowns above, but instead of the previous script how about:

<!-- a template dropdownlist - hidden from view -->
@Html.DropdownList("ddlTemplate", Model.StandardProductTypes, new {id = "ddlTemplate", style="display:none;"})
<script>
$('input[type="select"][name$="SelectedStandardProductTypeKey"]').each(function()
    {
       $('#ddlTemplate option').clone().appendTo($(this));
       var initValue $("name='" + $(this).attr("name") + "_Initial'").val();
       $(this).val(initValue);
    }
</script>

EDIT 2

If you still find the page to be unresponsive when the javascript is populating the dropdowns after trying the script in the edit above then I have another possible solution.

You would basically need to populate each dropdown with a source as a new List<SelectListItem> - each containing just the single selected option.

Populate an array of values (as per the original script), but then instead of immediately populating all the dropdowns have some javascript that populates the remaining values from the array when you drop the dropdownlist for the first time.

That way you only load the full list of 400 items once, and client side javascript only needs to do work when you click a dropdown, rather than all 30 dropdowns at page load time.

Upvotes: 0

Edi G.
Edi G.

Reputation: 2420

how about copy with jQuery?

$('#myDropDownlist1 option').clone().appendTo('#myDropDownlist2');

Upvotes: 1

Related Questions