【问题标题】:Incorrect List Model Binding indices when using HTML Helpers使用 HTML Helpers 时不正确的列表模型绑定索引
【发布时间】:2016-02-26 07:43:37
【问题描述】:

这是一个很难解释的问题,所以我会尝试使用项目符号。

问题:

  1. 用户可以在视图上使用动态行(集合)(添加/删除)
  2. 用户删除行并保存 (POST)
  3. 集合通过非顺序索引传回控制器
  4. 单步执行代码,一切看起来都很好,集合项、索引等。
  5. 呈现页面后,项目无法正确显示 - 它们全部减 1,因此在新的 0 位置复制顶部项目。

我的发现:

仅当在 Razor 代码中使用 HTML 助手时才会发生这种情况。 如果我使用传统的<input> 元素(不理想),它可以正常工作。

问题:

以前有人遇到过这个问题吗?或者有谁知道为什么会这样,或者我做错了什么?

请在下面查看我的代码,感谢您查看我的问题!

控制器:

    [HttpGet]
    public ActionResult Index()
    {
        List<Car> cars = new List<Car>
        {
            new Car { ID = 1, Make = "BMW 1", Model = "325" },
            new Car { ID = 2, Make = "Land Rover 2", Model = "Range Rover" },
            new Car { ID = 3, Make = "Audi 3", Model = "A3" },
            new Car { ID = 4, Make = "Honda 4", Model = "Civic" }

        };

        CarModel model = new CarModel();
        model.Cars = cars;

        return View(model);
    }

    [HttpPost]
    public ActionResult Index(CarModel model)
    {
        // This is for debugging purposes only
        List<Car> savedCars = model.Cars;

        return View(model);
    }

Index.cshtml:

如您所见,我有“Make”和“Actual Make”输入。一个是 HTML Helper,另一个是传统的 HTML Input。

    @using (Html.BeginForm())
{
    <div class="col-md-4">

        @for (int i = 0; i < Model.Cars.Count; i++)
        {
            <div id="car-row-@i" class="form-group row">
                <br />
                <hr />

                <label class="control-label">Make (@i)</label>
                @Html.TextBoxFor(m => m.Cars[i].Make, new { @id = "car-make-" + i, @class = "form-control" })

                <label class="control-label">Actual Make</label>
                <input class="form-control" id="car-make-@i" name="Cars[@i].Make" type="text" value="@Model.Cars[i].Make" />

                <div>
                    <input type="hidden" name="Cars.Index" value="@i" />
                </div>

                <br />

                <button id="delete-btn-@i" type="button" class="btn btn-sm btn-danger" onclick="DeleteCarRow(@i)">Delete Entry</button>

            </div>
        }

        <div class="form-group">
            <input type="submit" class="btn btn-sm btn-success" value="Submit" />
        </div>

    </div>
}

Javascript 删除功能

function DeleteCarRow(id) {

    $("#car-row-" + id).remove();

}

用户界面中发生了什么:

第 1 步(删除行) 第 2 步(提交表格) 第 3 步(结果)

【问题讨论】:

  • 在您的 POST 方法中,在 return View(model); 之前添加 ModelState.Clear();。如果这样可以解决问题,则表明您与删除项目相关的代码是错误的。
  • @StephenMuecke 非常感谢您的回复。添加ModelState.Clear(); 有效!我现在已将用于删除行的 JQuery 添加到我的 OP 中。你知道我错过了什么吗?删除行后,我是否需要在此函数中以某种方式更新模型?

标签: c# html asp.net-mvc razor


【解决方案1】:

这种行为的原因是HtmlHelper 方法使用来自ModelState 的值(如果存在)来设置value 属性而不是实际的模型值。此行为的原因在TextBoxFor displaying initial value, not the value updated from code 的回答中进行了解释。

在你的情况下,当你提交时,以下值被添加到ModelState

Cars[1].Make: Land Rover 2
Cars[2].Make: Audi 3
Cars[3].Make: Honda 4

请注意,Cars[0].Make 没有任何值,因为您删除了视图中的第一项。

当您返回视图时,集合现在包含

Cars[0].Make: Land Rover 2
Cars[1].Make: Audi 3
Cars[2].Make: Honda 4

所以在循环的第一次迭代中,TextBoxFor() 方法检查 ModelState 是否匹配,没有找到匹配项,并生成 value="Land Rover 2"(即模型值)并且您的手动输入也会读取模型值并设置value="Land Rover 2"

在第二次迭代中,TextBoxFor() 确实在ModelState 中找到了与Cars[1]Make 的匹配项,因此它设置value="Land Rover 2",手动输入读取模型值并设置value="Audi 3"

我假设这个问题只是为了解释行为(实际上,您将保存数据,然后重定向到 GET 方法以显示新列表),但您可以在返回视图时生成正确的输出通过调用ModelState.Clear(),这将清除所有ModelState 值,以便TextBoxFor() 根据模型值生成value 属性。

旁注:你的视图包含很多不好的做法,包括用行为污染你的标记(使用Unobtrusive JavaScript),创建不作为标签的标签元素(点击它们不会将焦点设置到关联的控件) ,不必要地使用 &lt;br/&gt; 元素(使用 css 为元素设置边距等)以及不必要地使用 new { @id = "car-make-" + i }。循环中的代码可以是

@for (int i = 0; i < Model.Cars.Count; i++)
{
    <div class="form-group row">
        <hr />
        @Html.LabelFor(m => m.Cars[i].Make, "Make (@i)")
        @Html.TextBoxFor(m => m.Cars[i].Make, new { @class = "form-control" })
        ....
        <input type="hidden" name="Cars.Index" value="@i" />
        <button type="button" class="btn btn-sm btn-danger delete">Delete Entry</button>
    </div>
}

$('.delete').click(function() {
    $(this).closest('.form-group').remove();
}

【讨论】:

  • 很棒的解释。这有很大帮助,非常感谢您抽出时间对我的标记发表评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
  • 2018-08-20
  • 1970-01-01
  • 1970-01-01
  • 2019-06-01
相关资源
最近更新 更多