【问题标题】:Post only checked values <input type='checkbox' name='Product.Categories[i].Id' value='x' /> to viewmodel仅将选中的值 <input type='checkbox' name='Product.Categories[i].Id' value='x' /> 发布到 viewmodel
【发布时间】:2020-10-03 21:35:45
【问题描述】:

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

我有这个Product

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
}

还有这个Category

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

还有这个EditVM

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 个。所以这是完美的。

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

[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 个复选框。如果我选择最后三个并使用 emmidiate 窗口并运行以下命令,我会得到以下结果:

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 个复选框。如果我选择复选框 2 和 4,我希望发布一个包含 2 个项目的数组,其中包含复选框 2 和 4 的值的 id。如何实现?

【问题讨论】:

    标签: c# arrays checkbox asp.net-core-mvc model-binding


    【解决方案1】:

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

    <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>
    }
    

    【讨论】:

    • 我已经删除了隐藏的输入。已检查的值已发布但未绑定。我更新了我的问题。如果我检查前 2 个项目,这些值将绑定到我的 Product.Categories 道具。 Product.Categories[0].Id 和 Product.Categories[1].Id 被填充,所以它的作品。但是,如果我跳过前两个值并检查最后 3 个值,则这些值已发布但未绑定。它尝试绑定 Product.Categories[2].Id、Product.Categories[3].Id 和 Product.Categories[4].Id。这不起作用,因为 Product.Categories[0].Id 和 Product.Categories[1].Id 不存在。我怎样才能做到这一点?
    猜你喜欢
    • 2015-10-06
    • 2011-03-10
    • 2016-07-19
    • 2023-03-10
    • 2010-12-31
    • 2018-08-22
    • 2014-11-21
    • 2020-10-10
    • 1970-01-01
    相关资源
    最近更新 更多