Выпадающее меню в 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 в течение последних нескольких дней, поэтому любые советы по улучшению вышеизложенного будут оценены.