【问题标题】:Create more than one object of the same type in the same view在同一视图中创建多个相同类型的对象
【发布时间】:2015-05-31 19:18:11
【问题描述】:

在我的创建视图中,我想让用户创建一个对象列表(相同类型)。因此,我在视图中创建了一个表格,包括每行中的每个输入字段。各个“可创建”对象的行数是固定的。

假设有一个类 Book 包括两个属性 title 和 author 并且用户应该能够两个创建 10 或更少的书。

我该怎么做?

我不知道如何将对象列表(已绑定)传递给控制器​​。我试过了:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ICollection<Book> bookList)
    {
        if (ModelState.IsValid)
        {
            foreach(var item in bookList)
                db.Books.Add(item);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(articlediscounts);
    }

在视图中是:

<fieldset>
    <legend>Book</legend>

    <table id="tableBooks" class="display" cellspacing="0" width="100%">
            <thead>
                <tr>
                    <th>Title</th>
                    <th>Author</th>
                </tr>
            </thead>
            <tbody>
                @for (int i = 0; i < 10 ;i++ )
                {
                    <tr>
                        <td>
                            <div class="editor-field">
                                @Html.EditorFor(model => model.Title)
                                @Html.ValidationMessageFor(model => model.Title)
                            </div>
                        </td>
                        <td>
                            <div class="editor-field">
                                @Html.EditorFor(model => model.Author)
                                @Html.ValidationMessageFor(model => model.Author)
                            </div>
                        </td>
                    </tr>
                }
            </tbody>
        </table>

    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>

由于 booklist 为空,它不起作用,我不知道如何将所有创建的对象放入此列表中。

如果您有任何建议,我将非常感谢。

【问题讨论】:

    标签: c# asp.net entity-framework asp.net-mvc-4


    【解决方案1】:

    Scott Hanselman 有一些关于将数组传递给 MVC 控件绑定的详细信息:http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

    本质上是:确保您的控件具有正确的名称:使用列表索引

    将你的 for 循环更改为:

    @for (int i = 0; i < 10 ; i++)
    {
        <tr>
            <td>
                <div class="editor-field">
                    <input type="text" name="book[" + i + "].Title" />
                </div>
            </td>
            <td>
                <div class="editor-field">
                    <input type="text" name="book[" + i + "].Author" />
                </div>
            </td>
        </tr>
    }
    

    这将自动绑定到您的发布操作。

    [HttpPost]
    public ActionResult Create(IList<Book> bookList)
    

    然后您可以根据需要显示/隐藏它们或使用 js/jquery 动态添加它们

    编辑:正如 Stephen Muecke 正确观察到的那样,上述答案仅涉及从表单+字段到 HttpPost 的绑定,这似乎是问题的重点。

    原帖中的帖子操作与视图不兼容。 OP 中有很多缺失的代码可能相关也可能不相关,但值得观察的是,如果您的视图是针对单个模型的,那么您在 ModelState.IsValid 上的失败代码需要返回单个模型,或者您的视图需要返回是IList(或类似的),否则您将无法获得服务器端验证(但如果您手动将其添加到&lt;input&gt;s,您仍然可以获得客户端验证)

    【讨论】:

      【解决方案2】:

      您使用@Html.EditorFor(model =&gt; model.Title) 的事实表明您已将视图中的模型声明为

      @model yourAssembly.Book
      

      它只允许回发一个Book,所以 POST 方法需要是

      public ActionResult Create(Book model)
      

      请注意,您当前的实现创建的输入看起来像

      <input id="Title" name="Title" ... />
      

      name 属性没有索引器(它们需要是 name="[0].Title"name="[1].Title" 等),因此无法绑定到集合,并且由于重复的 id 属性,它的 html 也是无效的。

      如果你想精确地创建 10 本书,那么你需要在 GET 方法中初始化一个集合并将该集合传递给视图

      public ActionResult Create()
      {
        List<Book> model = new List<Book>();
        for(int i = 0; i < 10;i++)
        {
          model.Add(new Book());
        }
        return View(model);
      }
      

      在视图中

      @model yourAssembly.Book
      @using (Html.BeginForm())
      {
        for(int i = 0; i < Model.Count; i++)
        {
          @Html.TextBoxFor(m => m[i].Title)
          @Html.ValidationMessageFor(m => m[i].Title)
          .... // ditto for other properties of Book
        }
        <input type="submit" .. />
      }
      

      当你 POST 到时,它现在将绑定到你的集合

      public ActionResult Create(List<Book> bookList)
      

      注意集合应该是List&lt;Book&gt;,以防您需要返回视图。

      但是,这可能会强制用户创建所有 10 本书,否则验证可能会失败(正如您使用 @Html.ValidationMessageFor() 所建议的那样)。更好的方法是使用 BeginCollectionItem 辅助方法 (refer example) 或按照 this answer 的客户端模板在视图中动态添加新的 Book 项。

      【讨论】:

      • “只允许回发一本书”是不正确的。 GET 的视图模型不需要匹配 POST 的模型。 post action 参数是基于表单中的字段绑定的,而不是视图的@model
      • @freedomn-m,查看 OP 视图中的代码 - 他们正在创建一个带有 name="title" 的输入和一个带有 name="Author" 的输入,这将回发到一个 Book 对象!跨度>
      • "@model yourAssembly.Book.. 它只允许您回发一本书" - 您关于仅发布一本书的声明是指@model - 而不是输入名称。带有m[i].Title 等的帖子的其余部分很好,只是那部分。
      • 仅当您不使用模型绑定、忽略验证、如果您返回视图等时它会失败等(根据您的回答),但我怀疑这不是 OP 想要的
      【解决方案3】:

      您需要发送一个包含书籍列表的 JSON 对象。所以第一件事就是创建一个这样的模型类:

      public class SavedBooks{
          public List<Book> Books { get; set; }
      }
      

      那么Book 类必须有这两个道具:

      public class Book {
         public string Title { get; set; }
         public string Author { get; set; }
      }
      

      接下来,更改您的控制器以使用此模型:

      [HttpPost]
      [ValidateAntiForgeryToken]
      public ActionResult Create(SavedBooks model)
      

      然后创建一个javascript方法(使用jQuery)来创建一个与控制器SavedBooks类的结构相匹配的JSON对象:

      var json = { Books: [ { Title: $('#title_1').val(), Author: $('#Author_1').val() } ,
                            { as many items as you want }
                          ]
                 };
      $.ajax(
      {
          url: "/Controller/Create",
          type: "POST",
          dataType: "json",
          data: json
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-03-24
        • 1970-01-01
        • 2020-06-02
        • 1970-01-01
        • 2017-05-07
        • 2019-11-15
        • 1970-01-01
        相关资源
        最近更新 更多