Post 只检查值 <input type='checkbox' name='Product.Categories[i].Id' value='x' /> 到 viewmodel

Post only checked values <input type='checkbox' name='Product.Categories[i].Id' value='x' /> to viewmodel

我在正确发布表单模型中的选中值时遇到了一些问题。

我有这个Productclass

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public byte[] Photo { get; set; }
    public int InStock { get; set; }
    public decimal Price { get; set; }
    public decimal Discount { get; set; }
    public decimal TotalPrice => Price - Discount;
    public int SupplierId { get; set; }
    public string SupplierName { get; set; }
    public IEnumerable<Category> Categories { get; set; }//Contains only the categories the product is bound to
}

还有这个Categoryclass

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

还有这个EditVMclass

public class EditVM
{
    public Product Product { get; set; }
    public IEnumerable<Category> Categories {get; set;}//Contains all the categories in the db
}

在我的 ProductController 中,我有 Edit 操作方法。

public async Task<IActionResult> Edit(int id)
{
    var product = await _productRepo.Get(id);
    if (product == null) return RedirectToAction(nameof(Index));
    var categories = await _categoryRepo.Get();
    var editVM = new EditVM()
    {
        Product = product,
        Categories = categories
    };
    return View(editVM);
}

在我看来,这是 HTML 我循环浏览类别的地方

@{var categoryIdList = @Model.Product.Categories.Select(x => x.Id); //Again, contains only the categories the Product is bound to (And gets the id's)
int counter = 0;}
@foreach (Category category in Model.Categories)//Loop through all the categories in the db
{
    if (categoryIdList.Contains(category.Id))
    {
        <input type="checkbox" name="Product.Categories[@counter].Id" value="@category.Id" checked />
    }
    else
    {
        <input type="checkbox" name="Product.Categories[@counter].Id" value="@category.Id" />
    }
    <label>@category.Name</label>
    { counter++;}
}

到目前为止一切都很好,到这里一切正常。如果我在数据库中有 5 个类别并且产品绑定到其中的 2 个,则会显示 5 个复选框并选中 2 个。所以这是完美的。

但是,问题是当我 select 或取消 select 复选框时。现在数据库中的每个 Categories.Id(选中或未选中)都发布到 HttpPost Edit 操作方法,我只想要发布的 ID 是 selected.

[HttpPost]
//Note the Product class contains an IEnumerable<Category> Categories prop for the categories the propduct is bound to. This is where the chechbox values must come in play...
public async Task<IActionResult> Edit(Product Product)
{
    var EditedProduct = await _productRepo.Update(Product);
    return RedirectToAction(nameof(Index));
}

我可以选择 EditPostVM 但这不是我的偏好。 (但如果这是我的问题的解决方案,则不禁止!)。也可以更改传入的视图模型。

一些额外的调试信息:所以我有 5 个类别,所以有 5 个复选框。如果我 select 最后三个并使用 emmidiate window 和 运行 以下命令我得到这些结果:

this.Request.Form.ElementAt(5)
{[Product.InStock, {120}]}
    Key: "Product.InStock"
    Value: {120}
this.Request.Form.ElementAt(6)
{[Product.SupplierName, {Kipleverancier}]}
    Key: "Product.SupplierName"
    Value: {Kipleverancier}
//Values above are from other form elements. And this works just fine. The problem is below...
this.Request.Form.ElementAt(7)
{[Product.Categories[2].Id, {3}]}
    Key: "Product.Categories[2].Id"
    Value: {3}
this.Request.Form.ElementAt(8)
{[Product.Categories[3].Id, {4}]}
    Key: "Product.Categories[3].Id"
    Value: {4}
this.Request.Form.ElementAt(9)
{[Product.Categories[4].Id, {5}]}
    Key: "Product.Categories[4].Id"
    Value: {5}

如何将这最后三个项目绑定到我的 Product.Categories 道具?

如果我选中前 2 个项目以及最后一个(5 个复选框中的),则前 2 个选中的项目值绑定到 Product.Categories。最后检查的项目值已发布,但未绑定...

基本上我有 5 个类别,所以有 5 个复选框。如果我 select 复选框 2 和 4,我想发布一个包含 2 个项目的数组,其中包含复选框 2 和 4 的值的 ID。如何实现?

您的 foreach 循环中有一个隐藏的输入,它会将所有类别发送到 post 编辑。只需删除它:

<input type="hidden" name="Product.Categories[@counter].Id" value="@category.Id" />

更新:

您可以在提交表单时使用jquery更改选中的复选框名称:

@model EditVM
@{
    var categoryIdList = @Model.Product.Categories.Select(x => x.Id); //Again, contains only the categories the Product is bound to (And gets the id's)
    int counter = 0;
}
<form asp-action="Edit" method="post">

    @foreach (Category category in Model.Categories)//Loop through all the categories in the db
    {
        if (categoryIdList.Contains(category.Id))
        {
            <input type="checkbox" name="Product.Categories[@counter].Id" value="@category.Id" checked />
        }
        else
        {
            <input type="checkbox" name="Product.Categories[@counter].Id" value="@category.Id" />
        }
        <label>@category.Name</label>
        { counter++; }
    }
    <input id="btn" type="submit" value="submit" />
</form>


@section scripts{ 
<script>
    $("input[type=checkbox]").on("click", function () {
        if ($(this).attr('checked')) {
            $(this).removeAttr('checked');
        } else {
            $(this).attr('checked','checked')
        }
    })

    $("#btn").on("click", function () {
    var x = 0;
    $("input[type = checkbox]").each(function () {
        if ($(this).attr('checked')) {
            $(this).attr('name', "Product.Categories[" + x + "].Id")
            x++;
        }
    })
})
</script>
}