用AJAX调用的响应填充div时,@ Html.Hidden的值错误 [英] @Html.Hidden has wrong value when populating a div with the response from an AJAX call

查看:73
本文介绍了用AJAX调用的响应填充div时,@ Html.Hidden的值错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的视图,其中包含一个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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆