如何处理ASP.NET MVC中动态生成的表单的输出?

时间:2021-07-12 05:54:39

Say you create a form using ASP.NET MVC that has a dynamic number of form elements.

假设您使用具有动态数量的表单元素的ASP.NET MVC创建表单。

For instance, you need a checkbox for each product, and the number of products changes day by day.

例如,每个产品都需要一个复选框,产品数量每天都在变化。

How would you handle that form data being posted back to the controller? You can't set up parameters on the action method because you don't know how many form values are going to be coming back.

您如何处理发布回控制器的表单数据?您无法在操作方法上设置参数,因为您不知道将返回多少表单值。

4 个解决方案

#1


5  

Just give each checkbox a unique name value:

只需为每个复选框指定唯一的名称值:

<input class="approveCheck" id="<%= "approveCheck" + recordId %>" 
 name="<%= "approveCheck" + recordId %>" type="checkbox" />

Then parse the list of form values in the Action, after submit:

然后在提交后解析Action中的表单值列表:

foreach (var key in Request.Form.Keys)
    {
        string keyString = key.ToString();
        if (keyString.StartsWith("approveCheck", StringComparison.OrdinalIgnoreCase))
        {
            string recNum = keyString.Substring(12, keyString.Length - 12);

            string approvedKey = Request.Form["approveCheck" + recNum];
            bool approved = !String.IsNullOrEmpty(approvedKey);
            // ...

You don't need to pass form values as arguments; you can just get them from Request.Form.

您不需要将表单值作为参数传递;你可以从Request.Form中获取它们。

One other option: write a model binder to change the list into a custom type for form submission.

另一个选择:编写模型绑定器以将列表更改为表单提交的自定义类型。

#2


2  

Per Craig's answer.. that is safer. There are quirks to posting multiple form elements with the same name. I would add that it would be wise to wrap the logic that makes the "collection" of controls in a way similar to WebForms. Web Forms prepend the container control's name and adds an index. For example, in a Repeater the form elements inside would be named (something like) RepeaterName_Element1, RepeaterName_Element2. When you go to get the elements out, you have to use FindControl or something of the sort.

Per Craig的答案......更安全。发布具有相同名称的多个表单元素有些怪癖。我想补充说,以类似于WebForms的方式包装使控件“集合”的逻辑是明智的。 Web窗体预先添加容器控件的名称并添加索引。例如,在Repeater中,里面的表单元素将被命名(类似)RepeaterName_Element1,RepeaterName_Element2。当你去获取元素时,你必须使用FindControl或类似的东西。

#3


2  

Depending on the binders you are using, this should work:

根据您使用的粘合剂,这应该工作:

<%var i = 0;
  foreach (var product (IList<ProductSelection>)ViewData["products"]) {%>
      <%=Html.Hidden(string.Format("products[{0}].Id", i), product.Id)%>
      <%=Html.Checkbox(string.Format("products[{0}].Selected", i))%>
      <%=product.Name%><br/>
<%}%>

...which will result in HTML something like this (notice the array notation on the names):

...这将导致HTML像这样(注意名称上的数组符号):

<input name="products[0].Id" type="hidden" value="123">
<input name="products[0].Selected" type="checkbox">
Widget
<input name="products[1].Id" type="hidden" value="987">
<input name="products[1].Selected" type="checkbox">
Gadget

...and the controller method that handles the post:

...以及处理帖子的控制器方法:

public ActionResult SelectProducts(IList<ProductSelection> products)
{
     ...
}

Upon binding, products parameter will contain two instances of ProductSelection.

绑定时,products参数将包含两个ProductSelection实例。

One caveat is that I have not used the new default binding for complex objects. Rather I am using either the NameValueDeserializer or CastleBind, both from MvcContrib. They both behave this way. I am guessing binding in the Beta will work the same way.

需要注意的是,我没有对复杂对象使用新的默认绑定。而是使用来自MvcContrib的NameValueDeserializer或CastleBind。他们都这样做。我猜测Beta中的绑定将以相同的方式工作。

#4


0  

Depending on your data, you could either output a 'CheckboxList' (which is not possible in the newer versions any more) and use a string[] parameter, or you could set up multiple forms and just modify the action.

根据您的数据,您可以输出'CheckboxList'(在较新版本中不再可能)并使用string []参数,或者您可以设置多个表单并只修改操作。

#1


5  

Just give each checkbox a unique name value:

只需为每个复选框指定唯一的名称值:

<input class="approveCheck" id="<%= "approveCheck" + recordId %>" 
 name="<%= "approveCheck" + recordId %>" type="checkbox" />

Then parse the list of form values in the Action, after submit:

然后在提交后解析Action中的表单值列表:

foreach (var key in Request.Form.Keys)
    {
        string keyString = key.ToString();
        if (keyString.StartsWith("approveCheck", StringComparison.OrdinalIgnoreCase))
        {
            string recNum = keyString.Substring(12, keyString.Length - 12);

            string approvedKey = Request.Form["approveCheck" + recNum];
            bool approved = !String.IsNullOrEmpty(approvedKey);
            // ...

You don't need to pass form values as arguments; you can just get them from Request.Form.

您不需要将表单值作为参数传递;你可以从Request.Form中获取它们。

One other option: write a model binder to change the list into a custom type for form submission.

另一个选择:编写模型绑定器以将列表更改为表单提交的自定义类型。

#2


2  

Per Craig's answer.. that is safer. There are quirks to posting multiple form elements with the same name. I would add that it would be wise to wrap the logic that makes the "collection" of controls in a way similar to WebForms. Web Forms prepend the container control's name and adds an index. For example, in a Repeater the form elements inside would be named (something like) RepeaterName_Element1, RepeaterName_Element2. When you go to get the elements out, you have to use FindControl or something of the sort.

Per Craig的答案......更安全。发布具有相同名称的多个表单元素有些怪癖。我想补充说,以类似于WebForms的方式包装使控件“集合”的逻辑是明智的。 Web窗体预先添加容器控件的名称并添加索引。例如,在Repeater中,里面的表单元素将被命名(类似)RepeaterName_Element1,RepeaterName_Element2。当你去获取元素时,你必须使用FindControl或类似的东西。

#3


2  

Depending on the binders you are using, this should work:

根据您使用的粘合剂,这应该工作:

<%var i = 0;
  foreach (var product (IList<ProductSelection>)ViewData["products"]) {%>
      <%=Html.Hidden(string.Format("products[{0}].Id", i), product.Id)%>
      <%=Html.Checkbox(string.Format("products[{0}].Selected", i))%>
      <%=product.Name%><br/>
<%}%>

...which will result in HTML something like this (notice the array notation on the names):

...这将导致HTML像这样(注意名称上的数组符号):

<input name="products[0].Id" type="hidden" value="123">
<input name="products[0].Selected" type="checkbox">
Widget
<input name="products[1].Id" type="hidden" value="987">
<input name="products[1].Selected" type="checkbox">
Gadget

...and the controller method that handles the post:

...以及处理帖子的控制器方法:

public ActionResult SelectProducts(IList<ProductSelection> products)
{
     ...
}

Upon binding, products parameter will contain two instances of ProductSelection.

绑定时,products参数将包含两个ProductSelection实例。

One caveat is that I have not used the new default binding for complex objects. Rather I am using either the NameValueDeserializer or CastleBind, both from MvcContrib. They both behave this way. I am guessing binding in the Beta will work the same way.

需要注意的是,我没有对复杂对象使用新的默认绑定。而是使用来自MvcContrib的NameValueDeserializer或CastleBind。他们都这样做。我猜测Beta中的绑定将以相同的方式工作。

#4


0  

Depending on your data, you could either output a 'CheckboxList' (which is not possible in the newer versions any more) and use a string[] parameter, or you could set up multiple forms and just modify the action.

根据您的数据,您可以输出'CheckboxList'(在较新版本中不再可能)并使用string []参数,或者您可以设置多个表单并只修改操作。