выпадающий в форме редактирования MVC3 - PullRequest
15 голосов
/ 28 января 2011

Это может быть очень просто, но я не могу разобраться сам. Я создал простой модал БД и сущностей, который выглядит следующим образом

enter image description here

Я пытаюсь создать форму создания, которая позволяет мне добавлять новый заказ. У меня есть в общей сложности 3 таблицы, поэтому я пытаюсь создать форму, позволяющую человеку ввести дату заказа, а также раскрывающийся список, в котором можно выбрать продукт из таблицы продуктов

Я хочу иметь возможность создать представление «Добавить» или «Изменить», которое позволит мне вставить OrderDate в OrderTable, а также вставить OrderID и выбранный ProductID в OrderProduct.

Какие шаги мне нужно сделать здесь.

Я создал OrderController и поставил отметку «Добавить действия», а затем добавил «Создать представление», которое выглядит следующим образом

@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, чтобы оно было выпадающим из Product 2. Как я могу получить данные из коллекции FormCollection? Я думал только о foreach, однако я не знаю, как получить строго напечатанное имя

Любая помощь для новичка была бы очень полезна.

Спасибо!

Ответы [ 3 ]

25 голосов
/ 17 февраля 2011

Во-первых, не связывайтесь с сущностью Order . Никогда не привязывайте к объекту 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; }
}

Вот и все.

Верните это в View в действии [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), который выводит Date 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 с избыточной таблицей соединений. Вы сгенерировали это из БД? Если это так, ваша БД, возможно, нуждается в работе.

У вас должно быть навигационное свойство под названием Products в сущности Order , которое ссылается на коллекцию Product , которая стала возможной благодаря автоматическому объединению в объединение стол во многих ко многим.

Это также означает, что у вас больше нет DropDownList, но есть MultiSelectDropDownList.

2 голосов
/ 07 октября 2011

Спасибо, Крейг.Ваши несколько дней (на момент публикации) MVC решили мои несколько дней попыток вернуть выбранное значение из DropDownListFor.

У меня не было проблем в представлении Создать при получении выбранного значения DDLF, но представление «Правка» было совершенно другим делом - я не пытался вернуть выбранное значение в сообщение.Я заметил, что выбранное значение скрывалось в AttemptedValue 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)

-в контроллере (Пост)

    contentKeyId = int.Parse(form.GetValue("ContentKey").AttemptedValue); 

все хорошо, и я могу заниматься более захватывающими вещами.Почему самые простые вещи могут так долго тебя удерживать?

1 голос
/ 17 февраля 2011

Я боролся с этим в течение последнего дня или около того тоже. Я поделюсь своими ограниченными знаниями в надежде, что это поможет кому-то еще.

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

...