【问题标题】:Ability to add child list items to ViewModel dynamically能够动态地将子列表项添加到 ViewModel
【发布时间】:2017-03-27 06:52:20
【问题描述】:

背景

我正在构建一个相当简单的库存和订单管理系统。在所有此类系统中,您最终会到达订单(在我的情况下为 PurchaseOrder)具有订单行项目列表(在我的应用程序中称为 LineItem)的位置。

后端代码

目前,我的 ViewModels 直接映射到我的实体,所以我的 PurchaseOrderVm 看起来像这样:

public class PurchaseOrderVm
{
  public PurchaseOrderVm()
  {
    LineItems = new List<LineItemVm>();
  }

  public int Id { get; set; }
  public DateTime Date { get; set; }
  public PurchaseOrderStatus Status { get; set; }
  [Display(Name = "Shipping Cost")]
  public decimal ShippingCost { get; set; }
  [Display(Name = "Import VAT")]
  public decimal Vat { get; set; }
  [Display(Name = "Import Duty")]
  public decimal ImportDuty { get; set; }
  [Display(Name = "Supplier Id")]
  public string SupplierId { get; set; }
  [Display(Name = "Supplier")]
  public string SupplierName { get; set; }
  public IEnumerable<LineItemVm> LineItems { get; set; }

  public List<SelectListItem> Suppliers { get; set; }

  public string ButtonText => Id != 0 ? "Update Purchase Order" : "Add Purchase Order";
}

而我的LineItemVm 看起来像这样:

public class LineItemVm
{
  public int Id { get; set; }
  public int Quantity { get; set; }
  public int OrderId { get; set; }
  [Display(Name = "Product")]
  public int ProductId { get; set; }
}

前端/用户体验

我知道我想要构建的体验类型,但我不确定自 MVC3 以来在这方面有多少进展。我想构建这个(强调重要性的位):

试过

只有通过这样做,我才能为单个 LineItem 工作:

<input class="form-control " id="ProductId" name="LineItems[0].ProductId" type="number" value="">

但显然这与动态相反。允许用户根据需要添加和删除项目并让表单和模型绑定器仍然有效的最简洁的方法是什么?

【问题讨论】:

  • 你可以查看这个关于收藏的链接。 c-sharpcorner.com/uploadfile/pmfawas/… 你要做什么 ` for (int i = 0; i Model.LineItems[i].ProductId) } `
  • 你用的是哪个前端框架??
  • 暂时没有,我希望只是香草 JS?
  • 一些选项请参考this answer
  • 你好慈湾。您是如何获得以下广泛而有用的答案的?对你有帮助吗?

标签: javascript c# asp.net-mvc asp.net-mvc-5


【解决方案1】:

您基本上可以使用客户端 JavaScript 代码构建新的订单项行。您需要确保输入元素(产品和数量)具有正确的名称属性值,以便模型绑定能够正常工作。

要使模型绑定起作用,您的输入名称应类似于 LineItems[0].ProductIdLineItems[0].Quantity(对于 row1)、LineItems[1].ProductIdLineItems[1].Quantity(对于 row2)等。

由于您需要为每一行提供一个产品下拉列表,我们将在页面中保留一个选择元素,并且每当我们需要添加新的行项目行时,我们将克隆该元素并将其用于该行。我们将使用 css 隐藏这个选择,因为这更像是一个查找数据,供我们根据需要进行克隆。

@model PurchaseOrderVm 
@using (Html.BeginForm("Add","Product"))
{
    @Html.LabelFor(f=>f.SupplierName)
    @Html.TextBoxFor(s=>s.SupplierName)

    <label>Order Products</label>
    <table id="items">
        <thead>
            <tr>
                <th>Product</th><th>Quantity</th>
            </tr>
        </thead>
        <tbody></tbody>
    </table>
    <button id="addProduct">Add Product</button>
    <input type="submit"/>
}
<SELECT Id="Products">
    <option value="1">Product 1</option>
    <option value="2">Product 2</option>
    <option value="3">Product 3</option>
</SELECT>

我对产品选择元素的内容进行了硬编码。您可以使用 Html.DropDownListFor/Html.DropDownList 辅助方法将其替换为来自服务器的数据

现在,在 addProduct 按钮上监听 click 事件,创建一个新行,添加 select 元素和数量 input 元素并将其附加到表中。单击删除链接时,只需删除最近的行并重新组织我们创建的其他输入的名称值。

$(function () {          

    $('#addProduct').click(function (e) {
        e.preventDefault();
        var rowIndex = $("#items>tbody>tr").length;
        var newRow = $("<tr/>");
        var p = $("#Products").clone()
              .attr("name", "LineItems[" + rowIndex + "].ProductId")
              .data("n","LineItems[r].ProductId").show();

        $("<td/>").append(p).appendTo(newRow);
        var q = $("<input />")
             .attr("name", "LineItems[" + rowIndex + "].Quantity")
             .data("n","LineItems[r].Quantity");
        var r = $("<a/>").attr("class", "remove").text("Remove");
        $("<td/>").append(q).append(r).appendTo(newRow);

        $("#items>tbody").append(newRow);

    });

    $("#items").on("click",".remove",function(e) {
        e.preventDefault();
        $(this).closest("tr").remove();
        //Re organize the input names
        $("#items>tbody>tr").each(function (rowIndex, row) {
            $(row).find("input").each(function(a, b) {
                var newName = $(b).data("n").replace("r", rowIndex);
                $(b).attr("name", newName);
            });
        });
    });

});

现在,当表单提交时,您的视图模型的 LineItems 属性将具有正确的数据。

[HttpPost]
public ActionResult Add(PurchaseOrderVm model)
{
  // check model.LineItems
  // to do : Return something
}

【讨论】:

    猜你喜欢
    • 2021-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-20
    相关资源
    最近更新 更多