【问题标题】:HTML.Textarea Values in MVC Razor ViewMVC Razor 视图中的 HTML.Textarea 值
【发布时间】:2013-05-10 15:29:24
【问题描述】:

我很难清楚地说明我遇到的问题。我试图了解如何在验证失败后在循环中创建的表单字段中保留值。我有一个更复杂的现实世界表单,其中包含在循环和验证中创建的一堆元素。我已将其简化为下面包含的一个简单示例。

当验证失败时,我希望在循环中创建的名为“Comment”的文本区域保留下面预提交图像中显示的值。

当我调试表单提交时,每个字段的值都成功连接到模型中名为 Comment 的 IList 变量。这就是我想要的,所以我可以循环并根据索引定位它们。

提交后,循环生成的每个文本区域都会显示模型中 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
    }
}


查看代码

@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" />
}


控制器代码

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;
        }
    }
}

【问题讨论】:

    标签: c# html asp.net-mvc razor model-binding


    【解决方案1】:

    如果验证失败,则返回模型。

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult TempTest(TempListModel model)
        {
            if (ModelState.IsValid)
            {
                return RedirectToAction("TempTest");
            }
            return View(model);
        }
    

    编辑改为在您的视图中尝试此操作

    @for (int i = 0; i < Model.Comment.Count(); i++)
    {
        <li>
            @Html.TextAreaFor(m => m.Comment[i], 4, 63, new { @title = "Comment" })
        </li>
    }
    

    让助手为你命名元素。你最终会得到name 属性,比如Comment[i]

    【讨论】:

    • 我刚刚修改了我的代码示例以使用视图而不是 RedirectToAction,因此更清楚的是 GetComments 函数没有覆盖这些值。我相信我当前的代码示例按照您的建议显示,但仍然存在同样的问题。
    • 谢谢。这成功了。每次我希望 html 字段连接到模型中的变量时,使用带有“For”的 html 生成器是否更合适?我正在使用的代码似乎连接变量主要是通过名称匹配来完成的,正如我在这里看到的那样,似乎并非在所有情况下都有效。
    • 我使用“For”版本,因为它更方便。在极少数情况下,您需要完全自定义并且不能依赖它。
    【解决方案2】:

    ASP.NET MVC 默认 ModelBinder 在请求中查找与 TempListModel 属性匹配的 HTML 名称,以在服务器中重新构建模型。但是您正在覆盖每个 HTML 元素的评论 ID:

    @Html.TextArea("Comment", Model.Comment[i], 4, 63, new { @id = "Comment_" + i, @title = "Comment" })
    

    如果您需要放置此自定义 ID,则必须创建一个新的 ModelBinder。 你可以像这样让事情变得简单:

      @Html.TextAreaFor(m => m.Comment[i], 4, 63, new { @title = "Comment" })
    

    希望对你有所帮助!

    【讨论】:

    • 你好法尔斯。感谢您查看这个。 Jasen 打败了你,但我很感激添加的解释,以帮助我进一步理解。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-09
    相关资源
    最近更新 更多