ASP.NET MVC: Каскадные зависимости в MVC 3 или зависимый DropDownListFor
Не так давно передо мной была поставлена задача реализовать в проекте ASP.NET MVC 3 некое подобие выпадающих списков (ComboBox или DropDownList) зависимых один от другого. Это значит, что данные обновляются в зависимости от другого Html-объекта. Задача была поставлена и решена.
Задача
Требуется реализовать обновление одного html-контрола в зависимости от выбранных данных в другом html-контроле. Что-то подобное уже было описано в статье для Silverlight, теперь настало время для ASP.NET MVC3.
О чем речь
Есть некоторое количество зависимых классов. Первый называется “город” (City):
public class City
{
public int Id { get; set; }
[StringLength(50), Required]
public string Name { get; set; }
}
Также можно допустить, что есть зависимый от города “район” (Disctrict):
public class District
{
public int Id { get; set; }
[StringLength(50), Required]
public string Name { get; set; }
public virtual City City { get; set; }
[ForeignKey("City"), Required]
public int CityId { get; set; }
}
А еще есть микрорайон (subdistrict), который теперь уже зависит от района:
public class Subdistrict
{
public int Id { get; set; }
[StringLength(50), Required]
public string Name { get; set; }
public virtual District District { get; set; }
[ForeignKey("District"), Required]
public int DistrictId { get; set; }
}
Наверное вы уже догадались, что мы будем работать с неким подобием адреса, а если говорить точнее, то мы будем создавать новый экземпляр типа адрес, в котором есть неотъемлемые части, такие как “Город”, “Район”, “Микрорайон”…. Для нашего примера этого достаточно.
Концепция
Есть три зависимые сущности, которые должны “правильно” отображать на странице ASP.NET MVC 3 сайта. При выборе города должен обновляться список районов, при смене района должен обновляться список микрорайонов.
Тонкости и необходимые условия
Для того чтобы всё заработало так как требуется – надо сделать в контроллере (Controller) два метода:
public JsonResult LoadDistricts(int id)
{
List<District> result = new List<District>();
var tmp = districtRepository.All.Where(x => x.CityId == id);
tmp.ToList().ForEach(x => result.Add(new District { Id = x.Id, Name = x.Name }));
return Json(result, JsonRequestBehavior.AllowGet);
}
и еще один:
public JsonResult LoadSubDistricts(int id)
{
List<Subdistrict> result = new List<Subdistrict>();
var tmp = subdistrictRepository.All.Where(x => x.DistrictId == id);
tmp.ToList().ForEach(x => result.Add(new Subdistrict { Id = x.Id, Name = x.Name }));
return Json(result, JsonRequestBehavior.AllowGet);
}
Тут важно заметить, что количество сущностей, которое должно быть возвращено на какой-либо форме, должно быть соответствовать тем методам в контроллере с пометкой JsonResult, которые вы хотите пользовать на страницах сайта.
Ключевое слово при добавлении нового объекта в базу данных – это валидация. Существует несколько видов – “серверная”, “клиентская”, я сейчас про “клиентскую”, еще ее называют, “валидация ввода”.

Итак, друзья мои, и недруги, будут вопросы – пишите в комментарии.