[英]how can I have multiple forms each generated from a list of items?
在 MVC 应用程序中,我有一个考试问题列表,我想在同一页面上向用户展示其中的一小部分,但每个答案都可以单独提交。 所以我的页面看起来像这样......
视图代码是....
@model List<QuestionResponseVM>
@for (int i = 0; i < Model.Count(); i++)
{
using (Html.BeginForm("CheckQuestions", "Checks", FormMethod.Post, new {questResponses = Model[i] }))
{
@Html.AntiForgeryToken()
@Html.HiddenFor(model => model[i].QuestionID)
<tr>
<td width="35%">
@Html.Raw(Model[i].QuestionText)
@Html.HiddenFor(model => model[i].QuestionText)
</td>
<td>
@Html.TextAreaFor(model => model[i].Response, new { @name = "DisplayTextEdit", @id = "DisplayTextEdit", @rows = 1, @cols = 80 })
</td>
<td width="30%">
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</div>
</td>
</tr>
}
}
我的问题是我只能将数据返回到问题 1 的 POST 方法。
这是 Controller 代码....
public class ChecksController : Controller
{
public ActionResult CheckQuestions()
{
return View(LoadQuestions());
}
// POST: Checks
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CheckQuestions(List<QuestionResponseVM> questResponses)
{
List<QuestionResponseVM> testList = new List<QuestionResponseVM>();
if (ModelState.IsValid)
{
testList = LoadQuestions(questResponses[0].QuestionID, questResponses[0].Response);
}
return View(testList);
}
private List<QuestionResponseVM> LoadQuestions (int _QuestionID = -1, string _Response = "")
{
List<QuestionResponseVM> thisList = new List<QuestionResponseVM>();
thisList.Add(new QuestionResponseVM()
{
QuestionID = 1,
QuestionText = "Question 1",
Response = (_QuestionID == 1 ? _Response : "")
});
thisList.Add(new QuestionResponseVM()
{
QuestionID = 2,
QuestionText = "Question 2",
Response = (_QuestionID == 2 ? _Response : "")
});
thisList.Add(new QuestionResponseVM()
{
QuestionID = 3,
QuestionText = "Question 3",
Response = (_QuestionID == 3 ? _Response : "")
});
return thisList;
}
}
如果 Controller POST 方法有一个QuestionResponseVM questResponses参数,这是我所期待的(希望),那么无论单击哪个“保存”按钮,视图都会返回 null。
但是,如果我将参数更改为列表(即List<QuestionResponseVM> questResponses ),那么问题 1 的“保存”按钮将返回一个包含单个项目和正确数据的列表。 但是,任何其他“保存”按钮(例如问题 2 或问题 3)都会返回 null 列表。
场景 1. 的行为对我来说似乎违反直觉,因为“开始表单”设置为返回单个 model 项目(模型实例),即“模型 [i]”。
在场景 2 中,我只是不明白为什么它适用于第一个表单(“保存”按钮)但不适用于其他表单。
我认为我不需要使用 JScript 或 AJAX 来执行此操作。
但很明显,我不是在这里“连接一些点”。
有人可以解释我观察到的行为,并可能给我一个正确的方向来满足这个要求。?
我将不胜感激任何帮助。
在回答您的问题之前,我不知道您的 forms 中的new {questResponses = Model[i] }))
正在做什么:
using (Html.BeginForm("CheckQuestions", "Checks", FormMethod.Post, new {questResponses = Model[i] }))
{
...
}
Model[i]
是一个复杂的 object。 你得到的只是 object 的名称:
由于您使用 for 循环来生成每个表单和表单中的输入,因此这些输入的名称将位于[INDEX].NAME
的 forms 中:
默认情况下,model 绑定会将这些输入(QuestionId、QuestionText 和 Response)绑定到匹配的 object。 QuestionResponseViewModel
确实匹配。 问题是[INDEX].
字首。
为了使默认的 model 绑定起作用,您在 POST 方法中声明的参数名称必须称为[INDEX]
,即第一种形式为[0]
,第二种形式为[1]
,依此类推:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CheckQuestions(QuestionResponseVM [0])
{
...
}
但是你知道我们不能在 C# 中声明类似的东西。
您可以使用foreach
生成每个表单,而不是使用常规的 for 循环。 这样,您就无需为每个表单命名一个正在更改的参数。
这里的另一个“GOTYOU”是 controller 中的参数必须与您在 for 循环中为每个QuestionResponseViewModel
声明的变量匹配:
@foreach (var qrVM in Model)
{
using(Html.BeginForm("..."))
{
@Html.AntiForgeryToken()
@Html.HiddenFor(x => qrVM.QuestionId)
<tr>
<td>
@Html.DisplayFor(x => qrVM.QuestionId)
@Html.HiddenFor(x => qrVM.QuestionId)
</td>
...
</tr>
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CheckQuestions(QuestionResponseVM qrVM)
{
// If you name the parameter something else, it won't bind!
...
}
如果您考虑一下,这是有道理的,因为您知道表单会将带有qrVM.QuestionId
、 qrVM.QuestionText
之类的键的数据发送回服务器。 默认的 model 绑定将搜索具有这些属性并命名为 qrVM 的qrVM
。
当第一个表单回传到服务器时,请求正文中的表单数据将如下所示:
[0].RequestionId: 1
[0].RequestionText: Question 1
[0].Response: xxx
MVC model 绑定仍然足够聪明,并且认为您正在发布您声明的列表的第一项。 因此,您将看到List<QuestionResponseVM> questResponses
捕获第一个表单的正确数据。
那么第二种和第三种形式呢? 例如,如果您在第二个表单上提交数据,请求正文中的表单数据将如下所示:
[1].RequestionId: 2
[1].RequestionText: Question 2
[1].Response: xxx
MVC model 绑定将其视为列表的第二项,但第一项在哪里? 而且它很困惑,因此无法将数据绑定到参数。 因此,您将从参数List<QuestionResponseVM> questResponses
。
您实际上不能像这样将表格放在表格内或表格行之间。 它被认为是无效的 HTML 结构。 无论如何,使用表格作为结构来在页面上显示数据从来都不是一个好主意。 相反,您可以使用 Bootstrap 的行和列。
我不知道为什么或什么让你认为你不应该需要 AJAX。 您的情况就像 go 的最佳方案,采用 AJAX 方法,例如,采用 AJAX。 用户可以单独保存每个问题的回答。 该页面不必刷新。
您在问题 1 上的保存按钮正在将表单提交到 controller。 您将需要在一组问题的末尾有一个保存/提交按钮并使用 FormCollection object 或花时间为每个按钮上的单击事件设置 JQuery/Ajax 并删除表单元素。 如果底部的按钮变成“下一个”,然后提交到 controller 以获取下一组相关问题,您可能会同时拥有两者。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.