繁体   English   中英

如何从项目列表中生成多个 forms?

[英]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;
    }
  }
  1. 如果 Controller POST 方法有一个QuestionResponseVM questResponses参数,这是我所期待的(希望),那么无论单击哪个“保存”按钮,视图都会返回 null。

  2. 但是,如果我将参数更改为列表(即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 的名称:

在此处输入图像描述


Q1:如果 Controller POST 方法只有一个参数

由于您使用 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.QuestionIdqrVM.QuestionText之类的键的数据发送回服务器。 默认的 model 绑定将搜索具有这些属性并命名为 qrVM 的qrVM

在此处输入图像描述


Q2:将参数更改为列表

当第一个表单回传到服务器时,请求正文中的表单数据将如下所示:

[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


我的 2 美分

  1. 您实际上不能像这样将表格放在表格内或表格行之间。 它被认为是无效的 HTML 结构。 无论如何,使用表格作为结构来在页面上显示数据从来都不是一个好主意。 相反,您可以使用 Bootstrap 的行和列。

  2. 我不知道为什么或什么让你认为你不应该需要 AJAX。 您的情况就像 go 的最佳方案,采用 AJAX 方法,例如,采用 AJAX。 用户可以单独保存每个问题的回答。 该页面不必刷新。

您在问题 1 上的保存按钮正在将表单提交到 controller。 您将需要在一组问题的末尾有一个保存/提交按钮并使用 FormCollection object 或花时间为每个按钮上的单击事件设置 JQuery/Ajax 并删除表单元素。 如果底部的按钮变成“下一个”,然后提交到 controller 以获取下一组相关问题,您可能会同时拥有两者。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM