Cascading DropdownがMVC3をリストします
-
25-10-2019 - |
質問
MVCにとっては比較的新しいものであり、電車の時間に動作するカスケードドロップダウンリストを取得しようとしています。
多くの投稿を見た後、人々はあなたがViewBag/ViewDataから離れて、代わりにViewModelsに集中するべきだと言いますが、私は頭を回すことができないようで、それは私を壁に駆り立てています。どんなチュートリアルも複雑であるか簡単すぎるように思われ、ビューモデル全体のアイデアはまだ私と一緒にクリックしていません。
だから私のシナリオは次のとおりです。私は、スタッフが個別の列車の旅を追加できる管理者システムを持っています。各電車の時間について、ユーザーが会社を選択できる入力フォームがあり、そこからドロップダウンリストがルートを示すジャーニー番号のリストを入力したいと思います。数字を選択したら、旅行の時間、電車の施設など、非常に大きいフォームの残りの部分を引き継ぐことができます。
私はそうするようなviewmodelを作成しました:
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.cascadingdropdownListforです。
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);
}