用AJAX调用的响应填充div时,@ Html.Hidden的值错误 [英] @Html.Hidden has wrong value when populating a div with the response from an AJAX call
问题描述
我有一个简单的视图,其中包含一个div
及其内部的部分视图.局部视图包含项目列表.每个项目要么显示为处于排除状态(标记为XXX),要么显示一个按钮以排除该项目(使用Ajax.BeginForm
)以提交Id
并更新其状态并重绘列表.
第一次绘制页面时,它可以正常工作,但是,在Ajax调用后重新渲染部分视图以排除某项时,而不是列表中的每一项都具有唯一的itemId
时,它们都具有itemId
表单提交中排除的项目.
Index.cshtml(主视图)
@model IEnumerable<StackOverflowMvc.Controllers.TestModel>
<div id="modelList">
@Html.Partial("ItemList", Model)
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
ItemList.cshtml(部分视图)
@model IEnumerable<StackOverflowMvc.Controllers.TestModel>
<ul>
@foreach (var item in Model)
{
<li>
<label>@item.Name</label>
@if(item.Excluded) {
<label>XXX</label>
} else {
using (Ajax.BeginForm("ExcludeItem", new AjaxOptions
{
HttpMethod = "post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "modelList"
})) {
@Html.Hidden("id", item.Id)
<!-- <input type="hidden" name="id" value="@item.Id" /> -->
<input type="submit" value="Check" />
}
}
</li>
}
</ul>
我可以通过注释掉@Html.Hidden
并取消注释隐藏的输入(在这种情况下,将正确的值设置为项目的ID)来使页面正常工作.
这是怎么回事?我使用Html.Hidden
或Ajax表单的方式有问题吗?还是不应该在这种情况下起作用?
HomeController.cs(以防万一)–
public class TestModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Excluded { get; set; }
}
public class HomeController : Controller
{
static List<TestModel> _items = new List<TestModel>{
new TestModel { Id=1, Name="Item 1", Excluded=false },
new TestModel { Id=2, Name="Item 2", Excluded=false },
new TestModel { Id=3, Name="Item 3", Excluded=false },
new TestModel { Id=4, Name="Item 4", Excluded=false }
};
public ActionResult Index()
{
return View(_items);
}
public ActionResult GetItems()
{
return PartialView("ItemList", _items);
}
[HttpPost]
public ActionResult ExcludeItem(int id)
{
_items.Find(x=>x.Id == id).Excluded = true;
return PartialView("ItemList", _items);
}
}
示例输出,以帮助说明问题:
模型加载页面时列出div
<div id="modelList">
<ul>
<li>
<label>Item 1</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form0" method="post">
<input id="id" name="id" type="hidden" value="1" /><!-- <input type="hidden" name="id" value="1" /> -->
<input type="submit" value="Check" />
</form> </li>
<li>
<label>Item 2</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form1" method="post">
<input id="id" name="id" type="hidden" value="2" /><!-- <input type="hidden" name="id" value="2" /> -->
<input type="submit" value="Check" />
</form> </li>
<li>
<label>Item 3</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form2" method="post">
<input id="id" name="id" type="hidden" value="3" /><!-- <input type="hidden" name="id" value="3" /> -->
<input type="submit" value="Check" />
</form> </li>
<li>
<label>Item 4</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form3" method="post">
<input id="id" name="id" type="hidden" value="4" /><!-- <input type="hidden" name="id" value="4" /> -->
<input type="submit" value="Check" />
</form> </li>
</ul>
</div>
提交后要排除项目2的
modelList(注意所有输入的值都为"2")
<div id="modelList">
<ul>
<li>
<label>Item 1</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form0" method="post">
<input id="id" name="id" type="hidden" value="2" /><!-- <input type="hidden" name="id" value="1" /> -->
<input type="submit" value="Check" />
</form> </li>
<li>
<label>Item 2</label>
<label>XXX</label>
</li>
<li>
<label>Item 3</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form1" method="post">
<input id="id" name="id" type="hidden" value="2" /><!-- <input type="hidden" name="id" value="3" /> -->
<input type="submit" value="Check" />
</form> </li>
<li>
<label>Item 4</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form2" method="post">
<input id="id" name="id" type="hidden" value="2" /><!-- <input type="hidden" name="id" value="4" /> -->
<input type="submit" value="Check" />
</form> </li>
</ul>
</div>
问题是由以下事实引起的,即所有input
元素都具有相同的ID/名称(通过多个元素具有相同的元素) id导致无效的HTML),并且ASP.NET MVC正在基于来自ModelState
而不是您的模型的数据重新绑定输入(这是默认情况下用于返回具有用户输入值的表单的机制). /p>
要避免与ModelState
绑定,只需在POST操作中将其清除:
[HttpPost]
public ActionResult ExcludeItem(int id)
{
_items.Find(x=>x.Id == id).Excluded = true;
ModelState.Clear();
return PartialView("ItemList", _items);
}
我还建议更改呼叫Html.Hidden
,以避免将id重复为类似这样的内容:
@Html.Hidden("id", item.Id, new { @id = "id_" + item.Id });
这样,您的输入应呈现如下:
<input id="id_4" name="id" type="hidden" value="4" />
这是完全有效的,并且仍然可以正确绑定.
I have a simple view that contains a div
with a partial view inside of it. The partial view contains a list of items. Each item is either shown in an excluded state (marked with XXX) or is shown with a button to exclude the item (which uses Ajax.BeginForm
) to submit the Id
and to update its state and redraw the list.
When the page is first drawn, it works correctly, however when the partial view is re-rendered after an Ajax call to exclude an item, rather than each item in the list having its unique itemId
they all have the itemId
of the item that was excluded by the form submission.
Index.cshtml (Main View)
@model IEnumerable<StackOverflowMvc.Controllers.TestModel>
<div id="modelList">
@Html.Partial("ItemList", Model)
</div>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
ItemList.cshtml (Partial View)
@model IEnumerable<StackOverflowMvc.Controllers.TestModel>
<ul>
@foreach (var item in Model)
{
<li>
<label>@item.Name</label>
@if(item.Excluded) {
<label>XXX</label>
} else {
using (Ajax.BeginForm("ExcludeItem", new AjaxOptions
{
HttpMethod = "post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "modelList"
})) {
@Html.Hidden("id", item.Id)
<!-- <input type="hidden" name="id" value="@item.Id" /> -->
<input type="submit" value="Check" />
}
}
</li>
}
</ul>
I can get the page to work by commenting out the @Html.Hidden
and uncommenting the hidden input (in which case the correct value is set to the id of the item).
What’s going on here? Is there something wrong with the way I am using Html.Hidden
, or the Ajax form? Or is it just not supposed to work in this situation?
HomeController.cs (just in case it's relevant)
public class TestModel
{
public int Id { get; set; }
public string Name { get; set; }
public bool Excluded { get; set; }
}
public class HomeController : Controller
{
static List<TestModel> _items = new List<TestModel>{
new TestModel { Id=1, Name="Item 1", Excluded=false },
new TestModel { Id=2, Name="Item 2", Excluded=false },
new TestModel { Id=3, Name="Item 3", Excluded=false },
new TestModel { Id=4, Name="Item 4", Excluded=false }
};
public ActionResult Index()
{
return View(_items);
}
public ActionResult GetItems()
{
return PartialView("ItemList", _items);
}
[HttpPost]
public ActionResult ExcludeItem(int id)
{
_items.Find(x=>x.Id == id).Excluded = true;
return PartialView("ItemList", _items);
}
}
Sample output, to help illustrate the problem:
modelList div on page load
<div id="modelList">
<ul>
<li>
<label>Item 1</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form0" method="post">
<input id="id" name="id" type="hidden" value="1" /><!-- <input type="hidden" name="id" value="1" /> -->
<input type="submit" value="Check" />
</form> </li>
<li>
<label>Item 2</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form1" method="post">
<input id="id" name="id" type="hidden" value="2" /><!-- <input type="hidden" name="id" value="2" /> -->
<input type="submit" value="Check" />
</form> </li>
<li>
<label>Item 3</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form2" method="post">
<input id="id" name="id" type="hidden" value="3" /><!-- <input type="hidden" name="id" value="3" /> -->
<input type="submit" value="Check" />
</form> </li>
<li>
<label>Item 4</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form3" method="post">
<input id="id" name="id" type="hidden" value="4" /><!-- <input type="hidden" name="id" value="4" /> -->
<input type="submit" value="Check" />
</form> </li>
</ul>
</div>
modelList after submitting to exclude item 2 (notice all inputs have value="2")
<div id="modelList">
<ul>
<li>
<label>Item 1</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form0" method="post">
<input id="id" name="id" type="hidden" value="2" /><!-- <input type="hidden" name="id" value="1" /> -->
<input type="submit" value="Check" />
</form> </li>
<li>
<label>Item 2</label>
<label>XXX</label>
</li>
<li>
<label>Item 3</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form1" method="post">
<input id="id" name="id" type="hidden" value="2" /><!-- <input type="hidden" name="id" value="3" /> -->
<input type="submit" value="Check" />
</form> </li>
<li>
<label>Item 4</label>
<form action="/Home/ExcludeItem" data-ajax="true" data-ajax-method="post" data-ajax-mode="replace" data-ajax-update="#modelList" id="form2" method="post">
<input id="id" name="id" type="hidden" value="2" /><!-- <input type="hidden" name="id" value="4" /> -->
<input type="submit" value="Check" />
</form> </li>
</ul>
</div>
The issue is caused by the fact, that all the input
elements have the same id/name (by the way having more than one element with the same id leads to an invalid HTML) and that ASP.NET MVC is rebinding the inputs based on data from ModelState
not your model (this is mechanism which is by default used in order to return the form with values entered by user).
To avoiding binding from ModelState
simply clear it in your POST action:
[HttpPost]
public ActionResult ExcludeItem(int id)
{
_items.Find(x=>x.Id == id).Excluded = true;
ModelState.Clear();
return PartialView("ItemList", _items);
}
I would also suggest changing the call Html.Hidden
in order to avoid duplicated ids to something like this:
@Html.Hidden("id", item.Id, new { @id = "id_" + item.Id });
This way your inputs should be rendered like this:
<input id="id_4" name="id" type="hidden" value="4" />
Which is perfectly valid and will still bind properly.
这篇关于用AJAX调用的响应填充div时,@ Html.Hidden的值错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!