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.