在同一视图中创建多个相同类型的对象
本文关键字:同类型 对象 创建 视图 | 更新日期: 2023-09-27 17:52:15
在我的create视图中,我想为用户提供创建对象列表(相同类型)的可能性。因此,我在视图中创建了一个表,包括每行中的每个输入字段。每个"可创建"对象的行数是一个固定的数字。
假设有一个类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是空的,它不起作用,我不知道如何把所有创建的对象放在这个列表中。
如果您有任何建议,我将非常感谢。
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>
}
这将自动绑定到你的post动作。
[HttpPost]
public ActionResult Create(IList<Book> bookList)
你可以根据需要显示/隐藏这些,或者使用js/jquery动态添加它们
编辑:正如Stephen Muecke正确观察到的,上面的答案只考虑从form+字段到HttpPost的绑定,这似乎是问题的重点。
原帖子中的post动作与视图不兼容。OP中有相当多的缺失代码可能或可能不相关,但值得观察的是,如果您的视图是针对单个模型,那么您在ModelState.IsValid
上的失败代码需要返回单个模型或您的视图需要用于IList
(或类似),否则您将无法获得服务器端验证(但如果您手动将其添加到<input>s
,您仍然可以获得客户端验证)
您使用@Html.EditorFor(model => 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<Book>
。
但是,这可能会强制用户创建所有10本书,否则验证可能会失败(正如您使用@Html.ValidationMessageFor()
所建议的那样)。一个更好的方法是在视图中动态添加新的Book
项,使用BeginCollectionItem辅助方法(参考示例)或根据这个答案使用客户端模板。
您需要发送一个JSON对象,其中包含图书列表。所以第一件事是创建一个像这样的Model类:
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)来创建一个JSON对象,该对象匹配控制器SavedBooks
类的结构:
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
});