简体   繁体   中英

HTML.Textarea Values in MVC Razor View

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

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

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] .

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:

 @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:

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

Hopes Its help you!

MVC Razor View simply you can use html

 <textarea name="Comment" autocomplete="off" class="textarea form-control" rows=1 >@Model.Comment</textarea>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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