Раскрывающийся список каскадных списков MVC3
-
25-10-2019 - |
Вопрос
Относительно новичок в MVC и попытка получить каскадный выпадающий список, работающий на поезде.
Посмотрев на множество постов, люди говорят, что вы должны держаться подальше от Viewbag/ViewData и вместо этого сосредоточиться на ViewModels, но я просто не могу поднять голову, и это заставляет меня вверх по стене. Любой учебник кажется либо сложным, либо слишком простым, и вся идея ViewModel еще не нажала со мной.
Итак, вот мой сценарий: у меня есть административная система, в которой сотрудники могут добавить отдельные поездки на поездах. Для каждого поезда у меня есть входная форма, в которой пользователь может выбрать компанию, и оттуда я бы хотел, чтобы внизу был заполнен списком номеров путешествий, которые указывают маршруты. Как только они выбрали ряд, они могут продолжать с остальной частью формы, которая довольно велика, включая время путешествия, удобства на поезде и т. Д.
Я создал ViewModel как SO:
public class JourneyNumbersViewModel
{
private List<SelectListItem> _operators = new List<SelectListItem>();
private List<SelectListItem> _journeys= new List<SelectListItem>();
[Required(ErrorMessage = "Please select an operator")]
public string SelectedOperator { get; set; }
[Required(ErrorMessage = "Please select a journey")]
public string SelectedJourney { get; set; }
public List<SelectListItem> Journeys
{
get { return _journeys; }
}
public List<SelectListItem> Operators
{
get
{
foreach(Operator a in Planner.Repository.OperatorRepository.GetOperatorList())
{
_operators.Add(new SelectListItem() { Text = a.OperatorName, Value = a.OperatorID.ToString() });
}
return _operators;
}
}
}
В моем контроллере у меня есть это для представления создания:
public ActionResult Create()
{
return View(new JourneyNumbersViewModel());
}
И это то, где это на самом деле не работает для меня - если я изменю свою модель в верхней части представления «Создание» на: @model Planner.ViewModels.JourneyNumbersViewModel
, затем остальная часть моей формы бросает ошибки, поскольку модель больше не верна для остальной части формы. Это так, как это должно работать - что, если вам нужно ссылаться на модели с несколькими представлениями с одним представлением?
Я знаю, что это простая вещь, и как только она щелкает, я задаюсь вопросом, как, черт возьми, я мог бы бороться с ней в первую очередь, но если кто -то сможет указать, куда я ошибаюсь, я был бы очень благодарен Анкет
Решение
Я сделал что -то подобное. Вот некоторые из кода (извиняюсь за то, что это было довольно длинным, но я хотел убедиться, что вы сможете воссоздать это на своей стороне):
Просмотр выглядит так:
using Cascading.Models
@model CascadingModel
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Cascading Forms</h2>
<table>
@using(Html.BeginForm("Index", "Home"))
{
<tr>
<td>@Html.LabelFor(m=>m.CategoryId)</td>
<td>@Html.DropDownListFor(m => m.CategoryId, new SelectList(Model.Categories, "Id", "Name"), string.Empty)</td>
</tr>
<tr>
<td>@Html.LabelFor(m=>m.ProductId)</td>
<td>@Html.CascadingDropDownListFor(m => m.ProductId, new SelectList(Model.Products, "Id", "Name"), string.Empty, null, "CategoryId", "Home/CategorySelected")</td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="Go"/></td>
</tr>
}
</table>
модель выглядит следующим образом:
public class CascadingModel
{
public int CategoryId { get; set; }
public List<Category> Categories { get; set; }
public int ProductId { get; set; }
public List<Product> Products { get; set; }
}
Настоящей «умной» частью системы является html.cascadingdropdownlist для, которая выглядит следующим образом:
public static class MvcHtmlExtensions
{
public static MvcHtmlString CascadingDropDownListFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
IEnumerable<SelectListItem> selectList,
string optionLabel,
IDictionary<string, Object> htmlAttributes,
string parentControlName,
string childListUrl
)
{
var memberName = GetMemberInfo(expression).Member.Name;
MvcHtmlString returnHtml = Html.SelectExtensions.DropDownListFor(htmlHelper, expression, selectList, optionLabel, htmlAttributes);
var returnString = MvcHtmlString.Create(returnHtml.ToString() +
@"<script type=""text/javascript"">
$(document).ready(function () {
$(""#<<parentControlName>>"").change(function () {
var postData = { <<parentControlName>>: $(""#<<parentControlName>>"").val() };
$.post('<<childListUrl>>', postData, function (data) {
var options = """";
$.each(data, function (index) {
options += ""<option value='"" + data[index].Id + ""'>"" + data[index].Name + ""</option>"";
});
$(""#<<memberName>>"").html(options);
})
.error(function (jqXHR, textStatus, errorThrown) { alert(jqXHR.responseText); });
});
});
</script>"
.Replace("<<parentControlName>>", parentControlName)
.Replace("<<childListUrl>>", childListUrl)
.Replace("<<memberName>>", memberName));
return returnString;
}
private static MemberExpression GetMemberInfo(Expression method)
{
LambdaExpression lambda = method as LambdaExpression;
if (lambda == null)
throw new ArgumentNullException("method");
MemberExpression memberExpr = null;
if (lambda.Body.NodeType == ExpressionType.Convert)
{
memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
}
else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpr = lambda.Body as MemberExpression;
}
if (memberExpr == null)
throw new ArgumentException("method");
return memberExpr;
}
}
Логика контроллера для тех, кто ищет это:
public ActionResult CategoriesAndProducts()
{
var viewModel = new CategoriesAndProductsViewModel();
viewModel.Categories = FetchCategoriesFromDataBase();
viewModel.Products = FetchProductsFromDataBase();
viewModel.CategoryId = viewModel.Categories[0].CategoryId;
viewModel.ProductId = viewModel.Products.Where(p => p.CategoryId).FirstOrDefault().ProductId;
return View(viewModel);
}