It is hard for me to clearly state the problem I am having. I am trying to understand how to retain values in form fields created in a loop after validation fails. I have a more complicated real world form that has a bunch of elements created in the loop and validation. I have reduced it to a simple example included below.
When validation fails I would like the textareas named "Comment" that have been created in the loop to retain the values that are shown in the Pre-Submit image below.
When I debug the form submission, the values from each of the fields are successfully connected to the IList variable named Comment found in the Model. This is what I want so I can loop through and locate them based on index.
After submitting, each textarea produced by the loop shows the comma separated representation of the IList variable Comment in the Model. It appears that the field in the view and in the model are connecting because they share a name. They connect properly on the way in but not on the way out. I would like the view to only show the value associated with the Comment[i] instead of the entire list so that the values remain constant between form submissions.
Screenshots and Sample Code Below
First Load:
Pre-Submit Form Changes:
Form as seen after first submit:
Form as seen after second submit:
Model Code
我很难清楚地说出我遇到的问题。我试图了解如何在验证失败后保留在循环中创建的表单字段中的值。我有一个更复杂的真实世界形式,在循环和验证中创建了一堆元素。我把它简化为一个简单的例子,包括在下面。当验证失败时,我希望在循环中创建的名为“Comment”的textareas保留下面的预提交图像中显示的值。当我调试表单提交时,每个字段的值都成功连接到模型中名为Comment的IList变量。这就是我想要的,所以我可以循环并根据索引找到它们。提交后,循环生成的每个textarea显示模型中IList变量Comment的逗号分隔表示。看起来视图和模型中的字段是连接的,因为它们共享一个名称。它们在进入途中正确连接,但在出路时没有连接。我希望视图只显示与Comment [i]相关的值而不是整个列表,以便值在表单提交之间保持不变。第一次加载下面的屏幕截图和示例代码:预先提交表单更改:首次提交后看到的表单:第二次提交后看到的表单:型号代码
using System.Collections.Generic;
namespace UI.Models.Forms
{
public class TempListModel : ContentModel
{
public TempListModel()
{
Comment = new List<string>();
}
public IList<string> Comment { get; set; } //Comments for each URL in the list
}
}
View Code
查看代码
@model UI.Models.Forms.TempListModel
@using (Html.BeginForm("temptest", "Test", new { id = 1 }, FormMethod.Post, new { id = "listForm", name = "listForm" }))
{
<ul>
@for (int i = 0; i < Model.Comment.Count(); i++)
{
<li>
<div class="llformlabel">
Notes:
<div>@Model.Comment[i]</div>
@Html.TextArea("Comment", Model.Comment[i], 4, 63, new { @id = "Comment_" + i, @title = "Comment" })</div>
</li>
}
</ul>
<input type="submit" value="Save Changes" />
}
Controller Code
控制器代码
using System.Collections.Generic;
using System.Web.Mvc;
using UI.Models.Forms;
namespace UI.Controllers
{
public class TestController : Controller
{
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult TempTest(TempListModel model)
{
//This function executes after the user submits the form.
//If server side validation fails then the user should be shown the form as it was when they submitted.
//model.Comment = GetComments(); //In my real world example this comes from a database.
if (true) //!ModelState.IsValid) //In my real world code this is a validation step that may fail
{
return View(model);
}
}
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult TempTest(int? id)
{
//In the real world example there is a lot going on in this function.
//It is used to load data from databases and set up the model to be displayed.
var model = new TempListModel();
model.Comment = GetComments();
return View("TempTest", "TempLayout", model);
}
private static IList<string> GetComments()
{
//Simple sample function used for demo purposes.
IList<string> comments = new List<string>();
comments.Add("Comment 1");
comments.Add("Comment 2");
comments.Add("Comment 3");
return comments;
}
}
}
2 个解决方案
#1
8
If you fail validation just return the model.
如果验证失败,则返回模型。
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult TempTest(TempListModel model)
{
if (ModelState.IsValid)
{
return RedirectToAction("TempTest");
}
return View(model);
}
Edit Try this in your view instead
编辑在您的视图中尝试此操作
@for (int i = 0; i < Model.Comment.Count(); i++)
{
<li>
@Html.TextAreaFor(m => m.Comment[i], 4, 63, new { @title = "Comment" })
</li>
}
And let the helper name the elements for you. You end up with name
attributes like Comment[i]
.
让助手为您命名元素。你最终得到了像Comment [i]这样的名字属性。
#2
2
ASP.NET MVC default ModelBinder looks for HTML names in the request that match TempListModel properties to build the model back in the server. But you are overriding the comment Id of each HTML Element:
ASP.NET MVC默认的ModelBinder在请求中查找与TempListModel属性匹配的HTML名称,以便在服务器中构建模型。但是你要覆盖每个HTML元素的注释ID:
@Html.TextArea("Comment", Model.Comment[i], 4, 63, new { @id = "Comment_" + i, @title = "Comment" })
If you need to place this custom ID, you must create a new ModelBinder. You can keep things easy like this:
如果需要放置此自定义ID,则必须创建新的ModelBinder。你可以像这样保持简单:
@Html.TextAreaFor(m => m.Comment[i], 4, 63, new { @title = "Comment" })
Hopes Its help you!
希望对你有所帮助!
#1
8
If you fail validation just return the model.
如果验证失败,则返回模型。
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult TempTest(TempListModel model)
{
if (ModelState.IsValid)
{
return RedirectToAction("TempTest");
}
return View(model);
}
Edit Try this in your view instead
编辑在您的视图中尝试此操作
@for (int i = 0; i < Model.Comment.Count(); i++)
{
<li>
@Html.TextAreaFor(m => m.Comment[i], 4, 63, new { @title = "Comment" })
</li>
}
And let the helper name the elements for you. You end up with name
attributes like Comment[i]
.
让助手为您命名元素。你最终得到了像Comment [i]这样的名字属性。
#2
2
ASP.NET MVC default ModelBinder looks for HTML names in the request that match TempListModel properties to build the model back in the server. But you are overriding the comment Id of each HTML Element:
ASP.NET MVC默认的ModelBinder在请求中查找与TempListModel属性匹配的HTML名称,以便在服务器中构建模型。但是你要覆盖每个HTML元素的注释ID:
@Html.TextArea("Comment", Model.Comment[i], 4, 63, new { @id = "Comment_" + i, @title = "Comment" })
If you need to place this custom ID, you must create a new ModelBinder. You can keep things easy like this:
如果需要放置此自定义ID,则必须创建新的ModelBinder。你可以像这样保持简单:
@Html.TextAreaFor(m => m.Comment[i], 4, 63, new { @title = "Comment" })
Hopes Its help you!
希望对你有所帮助!