javascript - 使用 AJAX 和 FormData 在 POST 上绑定(bind)列表

标签 javascript c# jquery ajax asp.net-core

我正在尝试将“产品规范”列表绑定(bind)到我的“添加产品”对话框。提交是使用 AJAX 执行的。

因为我允许用户在同一个表单上上传产品图片,所以我发送带有“FormData”对象的 AJAX 请求来代替序列化。

结果是,由于规范列表不是 Controller 预期的格式,因此永远不会达到 Controller 操作。

ProductModalViewModel

public class ProductModalViewModel
{
    public ProductModalViewModel()
    {
        Product = new Product();
        Specs = new List<Spec>();
    }
    public Product Product { get; set; }

    //Other properties removed for brevity

    public List<Spec> Specs { get; set; }
}

View (模态)

<form id="formSaveProduct" onsubmit="SaveProduct(event)" enctype="multipart/form-data">

<input type="hidden" asp-for="Product.Id" />

//Removed other form fields for brevity

<div class="specs-list-group">
    <ul class="list-group">
        @for (int i = 0; i < Model.Specs.Count(); i++)
        {
            <li class="list-group-item">
                <input type="hidden" asp-for="@Model.Specs[i].Id" />
                <div class="row">
                    <div class="col-5">
                        <input type="text" asp-for="@Model.Specs[i].Name" />
                    </div>
                    <div class="col-5">
                        <input type="text" asp-for="@Model.Specs[i].Value" />
                    </div>
                </div>
            </li>
        }
    </ul>
</div>
</form>

脚本

function SaveProduct(e) {
        e.preventDefault();  // prevent standard form submission

        $.ajax({
            url: "@Url.Action("SaveProduct", "ProductManagement", new { Area = "Admin" })",
            method: "post",
            data: new FormData($('#formSaveProduct')[0]),
            contentType: false,
            processData: false,
            success: function (result) {
                if (result.success) {
                    $("#exampleModal").modal('toggle');
                    location.reload();
                }
                else {
                    $(".modal-body").html(result);
                }
            },
            error: function (e) {
                alert("Error: " + e.status)
            }
        });
    }

Controller

 [HttpPost]
 public ActionResult SaveProduct(ProductModalViewModel model)
 {
     //Save
 }

请求头

FormData:

Product.Id: 1
Product.Brand: Browning
Product.Model: Gold Mossy Oak Shadow Grass Blades
Product.ProductNum: 723654
Product.CategoryId: 4
Product.IsActive: true
Product.Overview: This is an overview of the tkjsldfgn jlfdgl-sdfgn lkjgfnjkl dfsngkl kjlngkldf jngjkln kdfjnggf h sd sdfgdf...
Specs[0].Id: 1
Specs[0].Name: Test Spec 1
Specs[0].Value: Test Value 1
Specs[1].Id: 2
Specs[1].Name: Test Spec 2
Specs[1].Value: Test Value 2
Specs[2].Id: 3
Specs[2].Name: Test Spec 3
Specs[2].Value: Test Value 3

在我添加规范列表之前,此表单完全可以正常工作。在使用 FormData 对象时,我需要更改什么才能绑定(bind)列表?


编辑:添加了用于故障排除引用的规范实体。

public class Spec
{
    [Key]
    public int Id { get; set; }

    public Spec(string name, string value)
    {
        Name = name;
        Value = value;
    }

    [Required]
    public string Name { get; set; }

    [Required]
    public string Value { get; set; }

    [ForeignKey("Product")]
    [Required]
    public int ProductId {get; set; }
    public virtual Product Product { get; set; }

    //Timestamps
    public DateTime? Created { get; set; }
    public DateTime? Modified { get; set; }
}

最佳答案

修改 Controller 操作中的模型参数以使用 [FromForm] 属性:

[HttpPost]
public ActionResult SaveProduct([FromForm]ProductModalViewModel model)
{
    //Save
}

您可以阅读更多关于绑定(bind)行为的信息 here .

更新:

我怀疑您的问题来自两方面:

  1. 您的 Spec 类没有无参数构造函数
  2. ProductId 是 [必需],但您没有在 POST 中传递产品 ID

这是我的建议:

您真的不应该将实体模型放入您的 View 中。 我建议您创建一个名为 SpecDto 的新类并遵循这些规则

  1. 只添加您希望从客户提交的属性
  2. 有一个无参数的构造函数。
  3. 只使用相关属性。不要使用实体相关的属性,如 [ForeignKey("Product")]

像这样:

public class SpecDto
{
    public int Id { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public string Value { get; set; }

    public int ProductId { get; set; }

    public DateTime? Created { get; set; }
    public DateTime? Modified { get; set; }
}

你应该对产品做同样的事情。

那么你的 ViewModel 应该是这样的:

public class ProductModalViewModel
{
    public ProductModalViewModel()
    {
        Product = new ProductDto();
        Specs = new List<SpecDto>();
    }

    public ProductDto Product { get; set; }
    public List<SpecDto> Specs { get; set; }
}

然后在您的 Controller 中,将数据从 DTO 类传输到您的实体模型。我知道这看起来很乏味,但这是做这些事情的正确方法。如果你有一个大项目,请使用 AutoMapper传输数据。如果您的项目范围真的很小,那么也许您可以争论在您的 View 中使用实体模型的案例,但通常这不是一个好主意。

关于javascript - 使用 AJAX 和 FormData 在 POST 上绑定(bind)列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56280415/

相关文章:

javascript - 在 url 包含 2 个单独单词的页面上搜索 url

c# - 有没有办法检查是否所有定义的函数都被调用?

php - Ajax 调用 php 脚本返回 404 错误

javascript - 如何在使用 Angular 编写的 Web 和 PhoneGap 应用程序之间共享通用代码?

javascript - 如何使用 Javascript 从 XML 文档中提取值

javascript - 如何使用 angularjs 替换现有父 div 上的子 div?

c# - Linq Filtering items with ForEach crashes for large data set

c# - 是否有一个函数可以忽略像 'á' 'é' 'ó' 'í' 和 'ú' 这样的字符?

jquery - 将 css 媒体查询应用于响应式设计时 css 发生变化

javascript - 制作一个 Div,它的子元素是 Javascript 中的图像