无法通过 Html.BeginForm() 将数据从视图传递到操作 [英] Failing to pass data from view to the Action by Html.BeginForm()
问题描述
我是 asp.net mvc 的新手,所以我失败的原因也可能是基本的,但我现在工作了将近一天后似乎找不到它.
我想要做的是从索引视图中获取编辑后的模型并将其传递给没有视图的第二个操作并返回相关的返回 RedirectToAction("Index")
控制器.在 OrdersItemsController
中,我的操作如下:
[HttpPost][验证AntiForgeryToken]public ActionResult MarkedShipped(IEnumerable orderItems){如果(模型状态.IsValid){foreach (var item in orderItems){unitOfWork.GenericRepository().Update(item);}}return RedirectToAction("索引");}
在视图中 OrdersItems 文件夹中的 Index.cshtml 中,我所做的如下:
@model IEnumerable@{ViewBag.Title = "索引";}<h2>索引</h2>@using (Html.BeginForm("MarkedShipped", "OrdersItems", new { orderItems = Model })){@Html.AntiForgeryToken()@Html.ValidationSummary(true)<table class="table"><tr><th>@Html.DisplayNameFor(model => model.quantity)</th><th>@Html.DisplayNameFor(model => model.itemprice)</th><th>@Html.DisplayNameFor(model =>model.trackingnumber)</th></tr>@foreach(模型中的变量项目){<tr><td>@Html.DisplayFor(modelItem => item.quantity)</td><td>@Html.DisplayFor(modelItem => item.itemprice)</td><td>@Html.EditorFor(modelItem => item.trackingnumber)</td><td>@Html.ActionLink("Edit", "Edit", new { id = item.itemid })</td></tr>}<div class="form-group"><div class="col-md-offset-2 col-md-10"><input type="submit" value="MarkShipped" class="btn btn-default"/>
}
我的问题是,我无法从带有 orderItems 参数的视图中获取模型,我不确定这是否是我想要完成的正确语法";但是当操作被调用时,我得到的 orderItems
是一个 orders_items
列表,其中 Count = 0
不是空值.
我也检查过是否有应用程序级别的异常,但在 Global.asax
Application_Error
没有异常我现在被困了一天,所以如果有人能指出我如何将模型(或编辑过的数据")传递给我更新数据库的操作,我将不胜感激.谢谢.
首先,您不能将作为集合的模型(或包含作为复杂对象或集合的属性的模型)添加到表单路由参数.帮助程序在内部调用 .ToString()
方法,如果您检查为表单标记生成的 html,您将看到类似
并且绑定将失败,因为您的集合不能绑定到字符串.即使它确实有效,也没有意义,因为它只会回发模型的原始值.
接下来,您不能使用 foreach
循环来生成表单控件.同样,如果您检查生成的 html,您将看到 EditorFor()
方法正在生成具有重复 id
属性(无效 html)和重复 name的输入code> 属性,这些属性在您发布时没有绑定到集合的必要索引器.您需要为 typeof
orders_items
EditorTemplate
的 for
循环使用 for
循环意味着你的模型必须实现 IList
并且视图需要是
@model IList@using (Html.BeginForm())//仅当控制器和动作与GET方法不同时才需要添加{....@for(int i = 0; i < Model.Count; i++){@Html.DisplayFor(m => m[i].quantity)....@Html.EditorFor(m => m[i].trackingnumber)}....}
使用EditorTemplate
,在/Views/Shared/EditorTemplates/orders_items.cshtml
中创建一个partial(注意文件名必须与类名匹配)
@model Hochanda.CraftsHobbiesAndArts.DataAccess.orders_items<tr><td>@Html.DisplayFor(m => m.quantity)</td>....<td>@Html.EditorFor(m => m.trackingnumber)</td>....</tr>
然后在主视图中(你可以使用IEnumerable
)
@model IEnumerable@using (Html.BeginForm()){<table class="table"><头>....<头>@Html.EditorFor(m => m)</tbody>....}EditorFor()
方法接受 IEnumerable
并将根据 EditorTemplate
中的 html 为您集合中的每个项目生成一行代码>
在这两种情况下,如果您检查 html,您现在将看到模型在发布时绑定所需的正确名称属性
<input type="text" name="[1].trackingnumber" .../><input type="text" name="[3].trackingnumber" .../>
I am very new at asp.net mvc, so the reason behind my failure might be something basic as well, but I can't seem to find it after nearly a days work now.
What I am trying to do is to get the edited Model from the Index view and pass it to a second action which does not have view and returns return RedirectToAction("Index")
in the related controller. In OrdersItemsController
my Action is as the following:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult MarkedShipped(IEnumerable<orders_items> orderItems)
{
if (ModelState.IsValid)
{
foreach (var item in orderItems)
{
unitOfWork.GenericRepository<orders_items>().Update(item);
}
}
return RedirectToAction("Index");
}
And in the Index.cshtml which is in OrdersItems folder in the Views, what I did is as following:
@model IEnumerable<Project.DataAccess.orders_items>
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@using (Html.BeginForm("MarkedShipped", "OrdersItems", new { orderItems = Model }))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.quantity)
</th>
<th>
@Html.DisplayNameFor(model => model.itemprice)
</th>
<th>
@Html.DisplayNameFor(model => model.trackingnumber)
</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.quantity)
</td>
<td>
@Html.DisplayFor(modelItem => item.itemprice)
</td>
<td>
@Html.EditorFor(modelItem => item.trackingnumber)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.itemid })
</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="MarkShipped" class="btn btn-default" />
</div>
</div>
}
My problem is, I am not able to get the Model from the view with orderItems parameter, I am not sure if this is the right "syntax" for what I am trying to accomplish; but what I get for orderItems
when the action is called is a List of orders_items
with Count = 0
not a null value.
I have also checked if there is an application level exception, but got no exception from Application_Error
in Global.asax
I am stuck for a day now so If anyone can point me a direction on how to pass the Model (or "the edited data") to the action for me to update the db, I would be very grateful. Thanks.
解决方案 Firstly you cannot add a model which is a collection (or a model which contains a property which is a complex object or collection) to a forms route parameters. Internally the helper calls the .ToString()
method and if you inspect the html generated for your form tag you will see something like
<form action=OrdersItems/MarkedShipped?orderItems=System.Collection.Generic.......
and binding will fail since you collection cannot be bound to a string. Even if it did work, it would be rather pointless because it would just post back the original values of the model.
Next, you cannot use a foreach
loop to generate form controls. Again if you inspect the html your generating you will see that the EditorFor()
method is generating inputs with duplicate id
attributes (invalid html) and duplicate name
attributes which do not have the necessary indexers to bind to a collection when you post. You need to use either a for
loop of a custom EditorTemplate
for typeof orders_items
Using a for
loop means that your model must implement IList<T>
and the view needs to be
@model IList<Hochanda.CraftsHobbiesAndArts.DataAccess.orders_items>
@using (Html.BeginForm()) // only necessary to add the controller and action if they differ from the GET method
{
....
@for(int i = 0; i < Model.Count; i++)
{
@Html.DisplayFor(m => m[i].quantity)
....
@Html.EditorFor(m => m[i].trackingnumber)
}
....
}
Using an EditorTemplate
, create a partial in /Views/Shared/EditorTemplates/orders_items.cshtml
(note the name of the file must match the name of the class)
@model Hochanda.CraftsHobbiesAndArts.DataAccess.orders_items
<tr>
<td>@Html.DisplayFor(m => m.quantity)</td>
....
<td>@Html.EditorFor(m => m.trackingnumber)</td>
....
</tr>
and then in the main view (you can use IEnumerable<T>
)
@model IEnumerable<Hochanda.CraftsHobbiesAndArts.DataAccess.orders_items>
@using (Html.BeginForm())
{
<table class="table">
<thead>
....
<thead>
<tbody>
@Html.EditorFor(m => m)
</tbody>
</table>
....
}
The EditorFor()
method accepts IEnumerable<T>
and will generate one row for each item in you collection based on the html in the EditorTemplate
In both cases, it you inspect the html you will now see the correct name attributes necessary for you model to bind when you post
<input type="text" name="[0].trackingnumber" ... />
<input type="text" name="[1].trackingnumber" ... />
<input type="text" name="[3].trackingnumber" ... />
这篇关于无法通过 Html.BeginForm() 将数据从视图传递到操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文
登录
关闭
扫码关注1秒登录
发送“验证码”获取
|
15天全站免登陆