ASP.NET MVC 渲染视图并在动态生成的视图上验证失败时保留值

发布于 2024-08-12 07:04:15 字数 1304 浏览 12 评论 0原文

我正在尝试构建一个动态生成的视图。我的“创建”操作的控制器类看起来像这样

 public ActionResult Create()
 {
        List<FormMetadata> formItems = GetFormItems();

        return View(formItems);
 }

,到目前为止的视图是这样的,

<% using (Html.BeginForm())
   {%>
<table>
    <% foreach (var item in Model)
       {
           if (!item.IsActive)
           {
               continue;
           }
    %>
    <tr>
        <td>
            <%=Html.Encode(item.DisplayValue)%>
        </td>
        <td>
            <% 
                if (item.FieldType == "TextBox")
                {%>
            <%=Html.TextBox(item.Field, null, new { tabindex = item.SortOrder })%>
            <%}
                if (item.FieldType == "CheckBox")
                {%>
            <%=Html.CheckBox(item.Field, false, new { tabindex = item.SortOrder })%>
            <%}

            %>
        </td>
        <td>
        </td>
    </tr>
    <%} %>
</table>

我想显示相同的视图,并在出现验证错误时保留保留的值。类似下面的代码用于捕获验证错误

 if (string.IsNullOrEmpty(collection[item.ToString()]))
 {
         ModelState.AddModelError(key, "Required.");
 }

如何显示带有验证错误的视图,同时保留为此场景输入的值?

I'm trying to build a dynamically generated view. My controller class for Create action looks like this

 public ActionResult Create()
 {
        List<FormMetadata> formItems = GetFormItems();

        return View(formItems);
 }

and the View so far is something like this

<% using (Html.BeginForm())
   {%>
<table>
    <% foreach (var item in Model)
       {
           if (!item.IsActive)
           {
               continue;
           }
    %>
    <tr>
        <td>
            <%=Html.Encode(item.DisplayValue)%>
        </td>
        <td>
            <% 
                if (item.FieldType == "TextBox")
                {%>
            <%=Html.TextBox(item.Field, null, new { tabindex = item.SortOrder })%>
            <%}
                if (item.FieldType == "CheckBox")
                {%>
            <%=Html.CheckBox(item.Field, false, new { tabindex = item.SortOrder })%>
            <%}

            %>
        </td>
        <td>
        </td>
    </tr>
    <%} %>
</table>

I want to show the same view with the values retained when there are validation errors. Code like the following is used to catch the validation errors

 if (string.IsNullOrEmpty(collection[item.ToString()]))
 {
         ModelState.AddModelError(key, "Required.");
 }

How can I show a view with validation errors while retaining the values which have been entered for this scenario?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

满意归宿 2024-08-19 07:04:15

我会首先查看 NerdDinner 并基本上使用相同的方法。

I'd be checking out NerdDinner first and basically using the same approach.

煮酒 2024-08-19 07:04:15

EDIT2

我创建了一个可以运行的快速示例项目。我不喜欢一件事,那就是我无法传递列表本身。我每次都必须创建空白列表并从文本框中读取所有值并将其保存在列表中并将此更新后的列表提供给新视图。下一轮同样的事情。但它有效。

基本上:

    public ActionResult About() {
        List<FormMetaData> formItems = GetFormItems();

        return View(formItems);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult About(FormCollection form)
    {
        List<FormMetaData> formItems = GetFormItems();
        //TryUpdateModel(formItems);


        // update project members       
        foreach (var key in form.AllKeys) {
            if (key.ToString().StartsWith("TextBox")) {
                string field = (key.ToString().Replace("TextBox", ""));
                if (!string.IsNullOrEmpty(form.Get(key.ToString()))) {
                    formItems.Find(delegate(FormMetaData t) { return t.Field == field; }).Value = form.Get(key.ToString());
                } 
                else { }
                   // this.ProjectRepository.DeleteMemberFromProject(id, userId);
            }
        }

        ModelState.AddModelError("test", "this is a test error");
        if(ModelState.IsValid)
        {
                ///
        }
        else
        {
            return View(formItems);
        }
        return View(formItems);
    }

    private List<FormMetaData> GetFormItems() {
            List<FormMetaData> output = new List<FormMetaData>();

            FormMetaData temp1 = new FormMetaData("TextBox",true,"temp1","displayText1");
            FormMetaData temp2 = new FormMetaData("TextBox", true, "temp2", "displayText2");
            output.Add(temp1);
            output.Add(temp2);

            return output;
        }

然后你有你的观点:

<% using (Html.BeginForm()) {%>
<table>
    <% foreach (var item in Model) {
           if (!item.isActive) {
               continue;
           }   %>
    <tr>
        <td>
            <%=Html.Encode(item.DisplayValue)%>
        </td>
        <td>
            <% if (item.FieldType == "TextBox") {%>
            <%=Html.TextBox("TextBox"+item.Field, item.Value)%>
            <%} if (item.FieldType == "CheckBox") {%>
            <%=Html.CheckBox("Value")%>
            <%}%>
        </td>
        <td>
        </td>
    </tr>
    <%} %>
    <p>
            <input type="submit" value="submit" />
        </p>
      <% } %>
</table>

我已经为你上传了一个zip文件@ http://www .bastijn.nl/zooi/dynamicSample.rar

编辑

我已经尝试过这个示例,但模型绑定程序出了问题。当我使用“FormCollection 表单”作为 POST 创建方法的输入时,文本框的值位于提供的键下方。因此,您必须使用自定义模型绑定器或创建一个可与默认模型绑定器一起使用的模型。

更具体地说。它会出错,因为在这种情况下,您的文本框正在更新 List 内对象的属性,这是传递的 Model 。通常,您的文本框会更新对象内的属性,该对象也是您的模型,并且用于文本框(用于自动模型绑定)的键是您更新的属性的名称。

所以我认为模型绑定器不会将文本框中的值绑定到列表中的项目,因为它根本不知道如何自动执行此操作。现在是凌晨 3.17,所以我要去睡觉了,这个问题很有趣,我可能明天就能完成答案。

原始

<%=Html.TextBox(item.Field, null, new { tabindex = item.SortOrder })%>

看来您每次都会生成表单,并将值设置为null

尝试初始化它们,例如:

<%=Html.TextBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%>

在您的控制器中,当您检查 ModelState.isValid 时,执行以下操作:

if(ModelState.isValid){
     //code when it works
}
else{
    return View(formItems)    // these should contain the just added values
}

这应该可以解决问题。

因此,在一个简单的示例中,您会得到类似以下内容:

public ActionResult Create()
{
    List<FormMetadata> formItems = GetFormItems();

    return View(formItems);
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(List<FormMetadata> formItems)
{
    if(ModelState.isValid)
    {
        MyUpdate()
        save()
    }
    else
    {
        return view(formItems)
    }
}

以及您的观点:

<% 
   if (item.FieldType == "TextBox")
   {%>
         <%=Html.TextBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%>
         <%}
            if (item.FieldType == "CheckBox")
            {%>
              <%=Html.CheckBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%>
            <%}

EDIT2

I have created a quick sample project which works. There is one thing I do not like and that is that I cannot pass the list itself around. I have to create the blank list every time and read all the values from the textboxes and save this in the list and give this updated list to the new view. Next round same thing. But it works.

Basically:

    public ActionResult About() {
        List<FormMetaData> formItems = GetFormItems();

        return View(formItems);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult About(FormCollection form)
    {
        List<FormMetaData> formItems = GetFormItems();
        //TryUpdateModel(formItems);


        // update project members       
        foreach (var key in form.AllKeys) {
            if (key.ToString().StartsWith("TextBox")) {
                string field = (key.ToString().Replace("TextBox", ""));
                if (!string.IsNullOrEmpty(form.Get(key.ToString()))) {
                    formItems.Find(delegate(FormMetaData t) { return t.Field == field; }).Value = form.Get(key.ToString());
                } 
                else { }
                   // this.ProjectRepository.DeleteMemberFromProject(id, userId);
            }
        }

        ModelState.AddModelError("test", "this is a test error");
        if(ModelState.IsValid)
        {
                ///
        }
        else
        {
            return View(formItems);
        }
        return View(formItems);
    }

    private List<FormMetaData> GetFormItems() {
            List<FormMetaData> output = new List<FormMetaData>();

            FormMetaData temp1 = new FormMetaData("TextBox",true,"temp1","displayText1");
            FormMetaData temp2 = new FormMetaData("TextBox", true, "temp2", "displayText2");
            output.Add(temp1);
            output.Add(temp2);

            return output;
        }

and then you have your view:

<% using (Html.BeginForm()) {%>
<table>
    <% foreach (var item in Model) {
           if (!item.isActive) {
               continue;
           }   %>
    <tr>
        <td>
            <%=Html.Encode(item.DisplayValue)%>
        </td>
        <td>
            <% if (item.FieldType == "TextBox") {%>
            <%=Html.TextBox("TextBox"+item.Field, item.Value)%>
            <%} if (item.FieldType == "CheckBox") {%>
            <%=Html.CheckBox("Value")%>
            <%}%>
        </td>
        <td>
        </td>
    </tr>
    <%} %>
    <p>
            <input type="submit" value="submit" />
        </p>
      <% } %>
</table>

I have uploaded a zipfile for you @ http://www.bastijn.nl/zooi/dynamicSample.rar

EDIT

I have tried this example and it goes wrong with the modelbinder. When I use "FormCollection form" as input to the POST create method the values of my textboxes are there under the key supplied. So you have to either your custom model binder or make a model which will work with the default model binder.

To be more specific. It goes wrong because in this case your textboxes are updating properties in objects inside the List, which is the Model passed. Normally your textboxes are updating properties inside the Object which is also your Model and the key used for the textbox (for automatic modelbinding) is the name of the property you update.

So I suppose the model binder does not bind the values in the textbox to your items in the list since it simply does not know how to do this automatically. It is 3.17 am here right now so I'm off to bed, the question is interesting and I might finish the answer tomorrow.

original

<%=Html.TextBox(item.Field, null, new { tabindex = item.SortOrder })%>

It seems you are generating your form every time with the values set to null.

Try to init them something like:

<%=Html.TextBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%>

And in your controller, when you check for ModelState.isValid do something like:

if(ModelState.isValid){
     //code when it works
}
else{
    return View(formItems)    // these should contain the just added values
}

That should do the trick.

So, in a simple example you get something like:

public ActionResult Create()
{
    List<FormMetadata> formItems = GetFormItems();

    return View(formItems);
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(List<FormMetadata> formItems)
{
    if(ModelState.isValid)
    {
        MyUpdate()
        save()
    }
    else
    {
        return view(formItems)
    }
}

And your view:

<% 
   if (item.FieldType == "TextBox")
   {%>
         <%=Html.TextBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%>
         <%}
            if (item.FieldType == "CheckBox")
            {%>
              <%=Html.CheckBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%>
            <%}
南笙 2024-08-19 07:04:15

我现在使用以下方法,目前仅使用文本框

视图具有

<%
for (int i = 0; i < Model.Count; i++)
{
    var name = "formItems[" + i + "].Field";


    var htmlAttributes = new Dictionary<string, object>
                             {
                                 {"tabindex", Model[i].SortOrder},
                                 {"class", Model[i].ClientSideValidation}
                             };


%>
    <div> <%=Html.Encode(Model[i].DisplayValue)%> 
    <%=Html.TextBox(name, Model[i].DefaultValue, htmlAttributes)%> 
    <%= Html.ValidationMessage(Model[i].Field) %>
    </div>

<% } %>

控制器操作方法
GET

public ActionResult Create()
{
    List<FormMetadata> formItems = GetFormItems();

    HttpContext.Cache[FormCacheKey] = formItems;

    return View(formItems);
}

POST(部分代码)

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(List<FormMetadata> formItems)
    {
        var formDefinition = new List<FormMetadata>();

        try
        {
            if (HttpContext.Cache[FormCacheKey] != null)
            {
                formDefinition = HttpContext.Cache[FormCacheKey] as List<FormMetadata>;
            }
            else
            {
                formDefinition = GetFormItems();
                HttpContext.Cache[FormCacheKey] = formItems;
            }

            var formValues = new Dictionary<string, string>();

            for (int i = 0; i < formDefinition.Count; i++)
            {
                var key = formDefinition[i].Field;

                var value = formItems[i].Field ?? string.Empty;

I'm using the following approach now, only working with Textboxes at the moment

The View has

<%
for (int i = 0; i < Model.Count; i++)
{
    var name = "formItems[" + i + "].Field";


    var htmlAttributes = new Dictionary<string, object>
                             {
                                 {"tabindex", Model[i].SortOrder},
                                 {"class", Model[i].ClientSideValidation}
                             };


%>
    <div> <%=Html.Encode(Model[i].DisplayValue)%> 
    <%=Html.TextBox(name, Model[i].DefaultValue, htmlAttributes)%> 
    <%= Html.ValidationMessage(Model[i].Field) %>
    </div>

<% } %>

And the controller Action methods
GET

public ActionResult Create()
{
    List<FormMetadata> formItems = GetFormItems();

    HttpContext.Cache[FormCacheKey] = formItems;

    return View(formItems);
}

POST (part of the code)

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(List<FormMetadata> formItems)
    {
        var formDefinition = new List<FormMetadata>();

        try
        {
            if (HttpContext.Cache[FormCacheKey] != null)
            {
                formDefinition = HttpContext.Cache[FormCacheKey] as List<FormMetadata>;
            }
            else
            {
                formDefinition = GetFormItems();
                HttpContext.Cache[FormCacheKey] = formItems;
            }

            var formValues = new Dictionary<string, string>();

            for (int i = 0; i < formDefinition.Count; i++)
            {
                var key = formDefinition[i].Field;

                var value = formItems[i].Field ?? string.Empty;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文