Pour mettre en œuvre des listes déroulantes en cascade qui prennent en charge la validation et la liaison intégrées de MVC, vous devrez faire quelque chose d'un peu différent de ce qui est fait dans les autres réponses ici.
Si votre modèle comporte une validation, celle-ci sera prise en charge. Un extrait d'un modèle avec validation :
[Required]
[DisplayFormat(ConvertEmptyStringToNull = false)]
public Guid cityId { get; set; }
Dans votre contrôleur, vous devez ajouter une méthode get, afin que votre vue puisse obtenir les données pertinentes par la suite :
[AcceptVerbs(HttpVerbs.Get)]
public JsonResult GetData(Guid id)
{
var cityList = (from s in db.City where s.stateId == id select new { cityId = s.cityId, name = s.name });
//simply grabbing all of the cities that are in the selected state
return Json(cityList.ToList(), JsonRequestBehavior.AllowGet);
}
Venons-en maintenant à la vue que j'ai mentionnée plus tôt :
Dans votre vue, vous avez deux listes déroulantes semblables à celle-ci :
<div class="editor-label">
@Html.LabelFor(model => model.stateId, "State")
</div>
<div class="editor-field">
@Html.DropDownList("stateId", String.Empty)
@Html.ValidationMessageFor(model => model.stateId)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.cityId, "City")
</div>
<div class="editor-field">
@*<select id="cityId"></select>*@
@Html.DropDownList("cityId", String.Empty)
@Html.ValidationMessageFor(model => model.cityId)
</div>
Le contenu des listes déroulantes est lié par le contrôleur et est automatiquement alimenté. Remarque : d'après mon expérience, supprimer cette liaison et s'appuyer sur le java script pour remplir les listes déroulantes vous fait perdre la validation. En outre, la façon dont nous lions ici joue bien avec la validation, il n'y a donc aucune raison de la changer.
Passons maintenant à notre plugin jQuery :
(function ($) {
$.fn.cascade = function (secondaryDropDown, actionUrl, stringValueToCompare) {
primaryDropDown = this; //This doesn't necessarily need to be global
globalOptions = new Array(); //This doesn't necessarily need to be global
for (var i = 0; i < secondaryDropDown.options.length; i++) {
globalOptions.push(secondaryDropDown.options[i]);
}
$(primaryDropDown).change(function () {
if ($(primaryDropDown).val() != "") {
$(secondaryDropDown).prop('disabled', false); //Enable the second dropdown if we have an acceptable value
$.ajax({
url: actionUrl,
type: 'GET',
cache: false,
data: { id: $(primaryDropDown).val() },
success: function (result) {
$(secondaryDropDown).empty() //Empty the dropdown so we can re-populate it
var dynamicData = new Array();
for (count = 0; count < result.length; count++) {
dynamicData.push(result[count][stringValueToCompare]);
}
//allow the empty option so the second dropdown will not look odd when empty
dynamicData.push(globalOptions[0].value);
for (var i = 0; i < dynamicData.length; i++) {
for (var j = 0; j < globalOptions.length; j++) {
if (dynamicData[i] == globalOptions[j].value) {
$(secondaryDropDown).append(globalOptions[j]);
break;
}
}
}
},
dataType: 'json',
error: function () { console.log("Error retrieving cascading dropdown data from " + actionUrl); }
});
}
else {
$(secondaryDropDown).prop('disabled', true);
}
secondaryDropDown.selectedindex = 0; //this prevents a previous selection from sticking
});
$(primaryDropDown).change();
};
} (jQuery));
Vous pouvez copier le jQuery ci-dessus que j'ai créé, dans <script>...</script>
dans votre vue, ou dans un fichier script séparé si vous le souhaitez (notez que j'ai mis à jour ceci pour le rendre multi-navigateur, cependant le scénario que j'utilisais n'est plus nécessaire, il devrait fonctionner cependant).
Dans ces mêmes balises script, (pas dans un fichier séparé) vous pouvez appeler le plugin en utilisant le javascript suivant :
$(document).ready(function () {
var primaryDropDown = document.getElementById('stateId');
var secondaryDropdown = document.getElementById('cityId');
var actionUrl = '@Url.Action("GetData")'
$(primaryDropDown).cascade(secondaryDropdown, actionUrl);
});
N'oubliez pas d'ajouter le $(document).ready
la page doit être entièrement chargée avant que vous n'essayiez de faire en sorte que les listes déroulantes soient en cascade.