Выпадающее меню в mvc3
Это может быть очень просто, но я не могу разобраться в этом сам.
Я создал простой db и сущность модальный, который выглядит следующим образом
![enter image description here]()
Я пытаюсь создать форму "Создать", которая позволяет мне добавить новый заказ. У меня есть в общей сложности 3 таблицы, поэтому я пытаюсь создать форму, позволяющую человеку ввести дату заказа, а также выпадающий список, который позволяет мне выбрать продукт из таблицы продуктов.
Я хочу иметь возможность создать представление "Добавить" или "Изменить", которое позволит мне вставить OrderDate в OrderTable, а также вставить OrderID и выбранный ProductID в OrderProduct.
Какие шаги мне нужно сделать здесь.
Я создал OrderController и пометил "Добавить действия", а затем добавил Create View, который выглядит следующим образом:
@model Test.OrderProduct
@{
ViewBag.Title = "Create2";
}
<h2>Create2</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>OrderProduct</legend>
<div class="editor-label">
@Html.LabelFor(model => model.OrderID)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.OrderID)
@Html.ValidationMessageFor(model => model.OrderID)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.ProductID)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.ProductID)
@Html.ValidationMessageFor(model => model.ProductID)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
Это создает представление, содержащее текстовое поле для OrderID и ProductID, но не дату.
Мой контроллер CreatePost не был изменен
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
var data = collection;
// TODO: Add insert logic here
// db.Orders.AddObject(collection);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Мои вопросы:
1. Как я могу поменять текстовое поле ProductID на раскрывающееся меню, которое заполняется из продукта
2.Как получить данные из коллекции FormCollection? Я думал только о foreach, однако я не знаю, как получить строго типизированное имя
Любая помощь для новичков будет очень полезной.
Спасибо!
Ответы
Ответ 1
Прежде всего, не привязывайтесь к объекту Заказ. Никогда не привязывайтесь к объекту EF, всегда пытайтесь использовать ViewModel. Делает жизнь проще для представления, и в этом цель.
Итак, у меня есть ViewModel:
public class CreateOrderViewModel
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
public int SelectedProductId { get; set; }
public IEnumerable<SelectListItem> Products { get; set; }
}
Это прямо сейчас.
Верните это в свой вид в вашем действии контроллера [HttpGet]
:
[HttpGet]
public ActionResult Create()
{
var model = new CreateOrderViewModel
{
Products = db.Products
.ToList() // this will fire a query, basically SELECT * FROM Products
.Select(x => new SelectListItem
{
Text = x.ProductName,
Value = x.ProductId
});
};
return View(model);
}
Затем вынести список продуктов: (исключение основного HTML)
@model WebApplication.Models.CreateOrderViewModel
@Html.DropDownListFor(model => model.SelectedProductId, Model.Products)
Единственное, что я не знаю, как это сделать, - привязать к полю DateTime. Я предполагаю, что вам понадобится метод расширения (HTML Helper), который отображает дату Picker или что-то еще. Для этого представления (создания нового порядка) по умолчанию используется значение DateTime.Now
.
Теперь, на действие контроллера [HttpPost]
:
[HttpPost]
public ActionResult Create(CreateOrderViewModel model)
{
try
{
// TODO: this manual stitching should be replaced with AutoMapper
var newOrder = new Order
{
OrderDate = DateTime.Now,
OrderProduct = new OrderProduct
{
ProductId = SelectedProductId
}
};
db.Orders.AddObject(newOrder);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Теперь я также думаю, что ваша EF-модель нуждается в работе.
Для меня (на английском языке), Продукт может иметь много заказов, а заказ может иметь много продуктов.
Итак, это должно быть много-ко-многим. В настоящее время это 1-1 с избыточной таблицей соединения. Вы создали это из БД? Если это так, возможно, ваша БД должна работать.
У вас должно быть навигационное свойство Продукты на объекте Заказ, который ссылается на коллекцию Продукт, что стало возможным благодаря молчаливому соединению к таблице соединений во многих-ко-многим.
Это также означает, что у вас больше нет DropDownList, а MultiSelectDropDownList.
Ответ 2
Спасибо Крэйгу. Несколько дней (как во время публикации) MVC решили мои несколько дней, пытаясь вернуть выбранное значение из DropDownListFor.
У меня не возникло проблем в представлении Create при получении выбранного значения DDLF, но представление "Редактировать" было совершенно другим вопросом - ничто не пыталось получить выбранное значение в Post. Я заметил, что выбранное значение скрывалось в объекте "Попытка" ModelState, и поэтому Dr.Google сослался на меня здесь.
У меня было это на мой взгляд
@Html.DropDownList(model => model.ContentKeyID, Model.ContentKeys, Model.ContentKeyName)
где ContentKeys - это SelectList, заселяемый из БД через ViewModel, а ContentKeyName - выбранное в данный момент имя.
Самое странное, у меня есть другой DDL в представлении, заполненном одинаковым образом. Это работает. Почему, я не знаю. Это второй DDL в форме, но я не вижу, чтобы это имело значение.
Я читал где-то еще, возможно, было, что я использовал Guids как идентификатор, но это, похоже, не имело никакого значения - я перешел на Int32, но не думаю, что мне пришлось... я думаю, он перечисляет это не согласны с DDLF. Nullables, похоже, не имеет никакого значения.
Теперь, когда я добавил коллекцию форм в свой Post ActionResult и получаю выбранное значение с помощью
-view
@Html.DropDownList("ContentKey", Model.ContentKeys)
-in controller (Post)
contentKeyId = int.Parse(form.GetValue("ContentKey").AttemptedValue);
все хорошо, и я могу заняться более интересными вещами. Почему простейшие вещи могут удерживать вас так долго?
Ответ 3
Я боролся с этим в последний день или около того. Я поделюсь своими ограниченными знаниями в надежде, что это поможет кому-то другому.
Обратите внимание, что я использую singleton с предварительно заполненным списком, чтобы мой пример приложения был небольшим (т.е. не взаимодействовал с EF или DB).
Чтобы показать ProductList, вам понадобится элемент ViewBag или ViewData, содержащий ProductList.
Вы можете установить это в контроллере с помощью
ViewData["ProductList"] = new SelectList(Models.MVCProduct.Instance.ProductList, "Id", "Name", 1);
Затем обновите свой вид до чего-то вроде:
<div class="editor-field">@Html.DropDownList("ProductList")</div>
Для этапа Post/Create/Update вам нужно посмотреть FormCollection, чтобы получить результаты. Чтение других сообщений похоже на то, что здесь была ошибка, но теперь она исправлена, поэтому убедитесь, что у вас есть последняя. Для моего примера у меня есть DropDownList для продукта, поэтому я просто получаю выбранный идентификатор, а затем ища этот продукт в моем списке.
[HttpPost]
public ActionResult Create(FormCollection form )//Models.MVCOrder newOrder)
{
MVC.Models.MVCOrder ord = Models.MVCOrder.Instance.CreateBlankOrder();
//Update order with simple types (e.g. Quantity)
if (TryUpdateModel<MVC.Models.MVCOrder>(ord, form.ToValueProvider()))
{
ord.Product = Models.MVCProduct.Instance.ProductList.Find(p => p.Id == int.Parse(form.GetValue("ProductList").AttemptedValue));
ord.Attribute = Models.MVCAttribute.Instance.AttributeList.Find(a => a.Id == int.Parse(form.GetValue("attributeId").AttemptedValue));
UpdateModel(ord);
return RedirectToAction("Index");
}
else
{
return View(ord);
}
}
Я работаю только на MVC3 в течение последних нескольких дней, поэтому любые советы по улучшению вышеизложенного будут оценены.