【问题标题】:Serializing Form Subgroups for Ajax Submission to ASP.NET MVC为 ASP.NET MVC 的 Ajax 提交序列化表单子组
【发布时间】:2021-12-22 15:00:48
【问题描述】:

我正在创建一个应用程序,可以在其中创建一个注释,并且可以将一对多的零件添加到该注释中(该应用程序适用于客户要求拖拉机零件的拖拉机打捞场)。

我正在使用 Jquery AJAX 加载带有创建视图的弹出模式。我正在一个创建视图中创建一个包含其部分的注释。我的问题是我看不到从创建视图序列化表单数据的方法,以便控制器发布操作可以更新这两个类。当我有一个单独的页面和用于创建视图的 url 时,以前的一切都有效。我附上了创建视图的屏幕截图。

这是我的模型类:

public class Note
{
    public int ID { get; set; }
    public string CustomerName { get; set; }
    public string CustomerPhone { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateUpdated { get; set; }
    public string CreatedBy { get; set; }
    public string AssignedTo { get; set; }
    public virtual ICollection<Part> Parts { get; set; }
}

public class Part
{
     public int PartID { get; set; }
     public string PartNumber { get; set; }
     public string Description { get; set; }
     public int NoteID { get; set; }
     public virtual Note Note { get; set; }
}

我的发帖方式:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Note note)
{
        if (ModelState.IsValid)
        {
            db.Notes.Add(note);
            db.SaveChanges();
            return Json(new { success = true });
        }           

        return PartialView("CreateDialog", note);
}

我需要note 参数来包含视图中的数据。当我有一个单独的页面用于创建视图时,它在提交时正确地将包括Parts 在内的所有表单数据传递给note 参数。

第一个展示了如何在创建视图中添加多少部件来填充 Parts 属性:

但是当我尝试使用 jQuery 序列化并通过 ajax 提交时,我只得到了这个。即使填充了 Parts 输入字段:

最后是我的观点和 javascript。请向我解释如何修改 html,以便 serialize 也将获得这些部分,或者可能是 serialize 的替代品,我可以手动将数据附加到每个属性。

<h2>Create</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Note</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.CustomerName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.CustomerName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.CustomerName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.CustomerPhone, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.CustomerPhone, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.CustomerPhone, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.DateCreated, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.DateCreated, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.DateCreated, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.DateUpdated, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.DateUpdated, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.DateUpdated, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.CreatedBy, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.CreatedBy, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.CreatedBy, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.AssignedTo, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.AssignedTo, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.AssignedTo, "", new { @class = "text-danger" })
            </div>
        </div>


@*I am using js so the user can add part editors to this list. I have a part editor template (below) that this uses.*@ 
        <div class="parts-container create">         
             @Html.EditorFor(model => Model.Parts[p])            
        </div>

        <div id="btnWrapper">
            <input id="btnAddPart" type="button" value="Add Part" />
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

零件编辑器模板

@model CallNote.Models.Part
<div id="part-template" class="part-info">
    @Html.EditorFor(model => model.PartNumber, new { htmlAttributes = new { @class = "part-number" } })
    @Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class = "description" } })
    <input type="button" value="Delete" class="btn btn-default delete-button" />
    <br />
</div>
$.ajaxSetup({ cache: false });
    $(".create-button").click(function () {
        $(".ajax-content").load("/note/create", function (e) {
            $(".modal").modal({
                keyboard: true
            }, "show");
            bindForm(this);
        });
    });

    function bindForm(dialog) {
        $("form", dialog).submit(function () {
            $.ajax({
                url: this.action,
                type: this.method,
                data: $(this).serialize(),
                complete: function (xhr, status) {
                    if (status == "success") {
                        $(".modal").modal("hide");
                        location.reload();
                    } else {
                        alert("Failed: " + xhr.status + " " + xhr.statusText);
                    }
                }
            });
            return false;
        });
    }

【问题讨论】:

  • 而不是使用form.serialize()传递像data: { name: '" + $('#name').val() + "', age: " + $('#age').val() + " }这样的js对象
  • 我也强烈建议使用一些 js 库或框架,例如敲除
  • @sairfan 我意识到我可以做到。但我的问题是我如何使用子对象来做到这一点。会不会是这样的data: { name: '" + $('#name').val() + "', age: " + $('#age').val() + ", Parts: { partnumber: '" + $('#part-number').val() + "', and so on for other part properties } }

标签: jquery ajax asp.net-mvc forms


【解决方案1】:

您的场景中的问题是,当您使用 MVC HTML Helper 来呈现像输入对象这样的导航属性时,它将像这样呈现(如果我没记错的话)

<input type="text" name="Parts_PartNumber" value="part abc" />

它不会以 MVC 控制器能够理解的方式序列化以将其与模型绑定,因为你需要

<input type="text" name="Parts[0].PartNumber" value="part abc" />
<input type="text" name="Parts[1].PartNumber" value="part xyz" />

当您为零件编号动态创建新的输入控件时,您可以执行的操作还可以设置其名称属性,例如 name='Parts[0].PartNumber' 这是工作示例

public class CustomerViewModel
{
    public string CustomerName { get; set; }
    public IList<Part> Parts { get; set; }
}

public class Part
{
    public string PartName { get; set; }
}

控制器

[HttpPost]
public ActionResult Customer(CustomerViewModel customer)
{

    return Json(customer, JsonRequestBehavior.AllowGet);
}

查看

<form action="/Home/Customer" method="POST">

    <input name="CustomerName" value="abc" /> <br />
    <input name="Parts[0].PartName" value="xyz" />

    <button id="submitForm" type="submit">Submit</button>

</form>



@section scripts {

    <script type="text/javascript">

    $('form').submit(function () {

        console.log('click', this);


        var options = {
            url: '/Home/Customer',
            type: 'POST',
            data: $(this).serialize()
        }


        $.ajax(options)
        .done(function (response) {
            console.log('response: ', response);
        });

        return false;
    });


    </script>

或者其他方法可以是我们在 cmets 中讨论的 js 对象,在这种情况下它应该看起来像这样

data: { customerName: 'name', parts: [ {partName: 'part 1'},  {partName: 'part 2'}]}

您还可以循环遍历 html 中的输入对象并创建 json 或将序列化形式转换为有效的 json。

请注意,这可能不是一个理想的方法,但这是我可以帮助您解决问题的方法。

【讨论】:

  • 这个例子正是我想要的。我已经有一些像你说的那样命名部件的js,但是我认为js在我测试时不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-09
  • 1970-01-01
  • 1970-01-01
  • 2021-05-16
  • 2012-02-22
相关资源
最近更新 更多