简体   繁体   English

Ajax表单始终发布具有空值的ViewModel(MVC 4)

[英]Ajax form always posting ViewModel with null values (MVC 4)

Whenever I submit the form, the ViewModel object in the controller action has null (or default) values for every field in the ViewModel. 每当我提交表单时,控制器操作中的ViewModel对象在ViewModel中的每个字段都具有空(或默认)值。 The ViewModel object itself isn't null, but all of its values are null or default (0 for the ints, 1/1/0001 12:00:00 AM for the DateTimes, etc.). ViewModel对象本身不为null,但是其所有值均为null或默认值(对于ints来说是0,对于DateTimes是1/1/0001 12:00:00 AM,等等)。

After Googling this issue and seeing various suggestions, I've confirmed the following: 谷歌搜索此问题并看到各种建议后,我确​​认了以下内容:

  • The model state is valid. 模型状态有效。
  • The names in the HTML markup for each field exactly match the name of the parameter in the ViewModel (NewItem.ID, NewItem.AnotherID, etc.). HTML标记中每个字段的名称与ViewModel中的参数名称完全匹配(NewItem.ID,NewItem.AnotherID等)。
  • Changing the name of the parameter has no effect. 更改参数名称无效。

Why aren't the ViewModel values posting correctly? 为什么ViewModel值不能正确发布?

Here's what I have: 这是我所拥有的:

PaneViewModel PaneViewModel

public class PaneViewModel
{
    public ViewModel NewItem { get; set; }
    public DataTableViewModel DataTable { get; set; }
}

ViewModel 视图模型

[Table("TableName")]
public class ViewModel
{
    [Key]
    [Column(Order = 0)]
    [DisplayName("ID")]
    public int ID { get; set; }

    [Key]
    [Column(Order = 1)]
    [DisplayName("AnotherID")]
    public int AnotherID { get; set; }

    [Key]
    [Column(Order = 2)]
    [DisplayName("Some Date")]
    public DateTime SomeDate { get; set; }

    [Required]
    [DisplayName("Another Date")]
    public DateTime AnotherDate { get; set; }

    [DisplayName("A Third Date")]
    public DateTime? AThirdDate { get; set; }
}

View 视图

@using (Ajax.BeginForm("AddItem", "Controller", new AjaxOptions
{
    UpdateTargetId = "add-item-section",
    LoadingElementId = "loading-image",
    HttpMethod = "POST",
}))
{
    <section id="add-item-section">
        <table>
            <tr>
                <th>@Html.LabelFor(m => m.NewItem.SomeDate)</th>
                <th>@Html.LabelFor(m => m.NewItem.AnotherDate)</th>
                <th>@Html.LabelFor(m => m.NewItem.AThirdDate)</th>
                <th></th>
            </tr>
            @Html.EditorFor(m => m.NewItem, "ViewModelEditorTemplate")
        </table>
    </section>
}

View Model Editor Template 查看模型编辑器模板

@model ViewModel

<tr>
    <td>@Html.EditorFor(m => m.SomeDate)</td>
    <td>@Html.EditorFor(m => m.AnotherDate)</td>
    <td>@Html.EditorFor(m => m.AThirdDate)</td>
    <td><button type="submit" class="btn btn-info">Add</button></td>
</tr>

@Html.HiddenFor(m => m.ID)
@Html.HiddenFor(m => m.AnotherID)

Controller 调节器

[HttpPost]
public ActionResult AddItem(ViewModel item)
{
    // Breakpoint set here (code removed because it's irrelevant to this issue).
}

The Model binder is going to be attempting to match up those names NewItem.ID etc to the properties on the ViewModel class. 模型绑定器将尝试将那些名称NewItem.ID等与ViewModel类的属性进行匹配。 Unfortunately the Model binder will not automatically know to drop the NewItem preface when binding to your object. 不幸的是,当绑定到对象时,模型绑定器将不会自动知道删除NewItem前言。

If you accept an object of type ParentViewModel (or whatever your initial Model is called), this should allow the Model binder to initialize the ParentViewModel.NewItem with the properties from the form correctly. 如果您接受类型为ParentViewModel的对象(或任何称为初始Model的对象),则这应允许Model绑定程序正确地使用表单中的属性初始化ParentViewModel.NewItem

[HttpPost]
public ActionResult AddItem(ParentViewModel item)
{
   ViewModel newItem = item.NewItem;// <-- bound using the name to properties mapping
}

If this is not desirable, you can always implement a custom Model Binder but that is probably overkill for this issue. 如果这不是理想的选择,则可以始终实现自定义Model Binder,但这可能对这个问题来说是过高的选择。

EDIT 编辑

Stephen also pointed out the alternative of using a binding prefix to explicitly tell the ModelBinder to expect NewItem before the properties. Stephen还指出了使用绑定前缀来明确告诉NewItem在属性之前使用ModelBinder的替代方法。

[HttpPost]
public ActionResult AddItem([Bind(Prefix="NewItem")]ViewModel item)
{
   //item should be bound using the properties correctly
}

Depending on your preference, either of these solutions should work for you. 根据您的偏好,这些解决方案中的任何一种都可以为您工作。

From what I could see , you forgot to instantiate the Form for the ajax call . 从我可以看到的情况下,您忘了为ajax调用实例化Form。 To do this , use the helper Ajax.BeginForm , as shown in the example below . 为此,请使用辅助程序Ajax.BeginForm,如下面的示例所示。

@using (Ajax.BeginForm("MyAction", "MyController",
        new AjaxOptions {
            HttpMethod = "POST",
            InsertionMode = InsertionMode.Replace,
            UpdateTargetId = "target"})) 
{
        <tr>
            <td>@Html.EditorFor(m => m.SomeDate)</td>
            <td>@Html.EditorFor(m => m.AnotherDate)</td>
            <td>@Html.EditorFor(m => m.AThirdDate)</td>
            <td><button type="submit" class="btn btn-info">Add</button></td> 
        </tr>
        @Html.HiddenFor(m => m.ID) 
        @Html.HiddenFor(m => m.AnotherID)  
}

For more information about Ajax Helpers, please visit http://www.blackbeltcoder.com/Articles/script/using-ajax-beginform-with-asp-net-mvc 有关Ajax帮助程序的更多信息,请访问http://www.blackbeltcoder.com/Articles/script/using-ajax-beginform-with-asp-net-mvc

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM