首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >嵌套BeginCollectionItem

嵌套BeginCollectionItem
EN

Stack Overflow用户
提问于 2012-03-05 23:32:13
回答 3查看 10.6K关注 0票数 12

我使用Sanderson的BeginCollectionItem方法添加动态内容。当我在第一层做的时候,一切都很好。但是,当尝试在另一个BeginCollectionItem中实现一个嵌套集合即一个BeginCollectionItem时,它似乎不起作用。

我的模型如下:

代码语言:javascript
复制
public class Order
{

        [Key]
        [HiddenInput]
        public int id { get; set; }

        [Display(Name = "Order number")]
        public string number { get; set; }

        ...

        [Display(Name = "Payment method")]
        public List<PaymentMethod> payment_methods { get; set; }

        ...
}

public class PaymentMethod
{
        public MethodOfPayment method { get; set; }
        public CC cc { get; set; }
        public CASH cash { get; set; }
        public TT tt { get; set; }
}

public class TT
{
        [Key]
        public int id { get; set; }

        [Required(ErrorMessage = "{0} is required.")]
        [Display(Name = "Total amount")]
        public double? total_value { get; set; }

        ...

        [Display(Name = "Transfers")]
        public List<Transfer> transfers { get; set; }
}

public class Transfer
{
        [Key]
        public int id { get; set; }

        [Display(Name = "Payment")]
        public int payment_id { get; set; }

        [Required(ErrorMessage = "{0} is required.")]
        [Display(Name = "SWIFT")]
        public string swift { get; set; }

        [Required(ErrorMessage = "{0} is required.")]
        [Display(Name = "Amount transferred")]
        public double? transfer_amount { get; set; }

        [Required(ErrorMessage = "{0} is required.")]
        [Display(Name = "Date transferred")]
        public DateTime transfer_date { get; set; }

        ...
}

现在我得到的是一个可能有几种付款方式的订单,如果其中一种付款方式是TT (电传转帐),它可能会涉及几个转帐。当一个集合工作时,在一个订单中实现几种支付方法,但是当我试图在TT中实现几个传输时,这些传输中的任何一个都不会传递给控制器。

以下是我的观点:

代码语言:javascript
复制
@model prj.Models.Model.Order

@using (Html.BeginForm("Create")){
@Html.ValidationSummary(true, "Creation was unsuccessful. Please correct the errors and try again.")

...

@Html.TextBoxFor(m => m.number, new { id = "txtnumber" })

...


<div id="editorPaymentRows">
    @foreach (var payment in Model.payment_methods)
    {
        @Html.Partial("_NewPayment", payment)
    }
</div>

}

在_NewPayment部分:

代码语言:javascript
复制
@using prj.Helpers 
@model prj.Models.Model.PaymentMethod

<div class="editPaymentRow">

@using (Html.BeginCollectionItem("payment_methods"))
{
...

<div class="editor-label">
    @Html.LabelFor(m => m.tt.total_value)<req>*</req>      
</div>

<div class="editor-field">
    @Html.TextBoxFor(m => m.tt.total_value)
</div>

...


<div id="editorTransferRows">
   @if (Model.tt != null)
{
    foreach (var transfer in Model.tt.transfers)
    {
         @Html.Partial("_NewTransfer", transfer)
    }
}
...
</div>



}

</div>

最后,在_NewTransfer部分:

代码语言:javascript
复制
@using prj.Helpers 
@model prj.Models.Model.Transfer
...

<div class="editTransferRow">
//using (Html.BeginCollectionItem("transfers"))
@using (Html.BeginCollectionItem("tt.transfers"))
{
...

<div class="editor-label">
    @Html.LabelFor(m => m.swift)<req>*</req>      
</div>

<div class="editor-field">
    @Html.TextBoxFor(m => m.swift, new { @class = "t_swift" })
</div>

...

<div class="editor-label">
    @Html.LabelFor(m => m.transfer_amount)<req>*</req>      
</div>

<div class="editor-field">
    @Html.TextBoxFor(m => m.transfer_amount, new { @class = "t_transfer_amount" })
</div>

...
}

</div>

所以一切都正常,除了在控制器中,位于PaymentMethods的TT属性中的列表传输始终为空。它没有被正确地传递给控制器。我遗漏了什么吗?

嵌套BeginCollectionItem不起作用吗?我还得多走一步吗?请放点光。谢谢

我使用Joe的方法解决了这个问题,如下面的链接所示:

http://www.joe-stevens.com/2011/06/06/editing-and-binding-nested-lists-with-asp-net-mvc-2/

干杯

EN

回答 3

Stack Overflow用户

发布于 2013-08-20 21:05:36

要获得带有Html.BeginCollectionItem的前缀,您可以访问ViewData.TemplateInfo.HtmlFieldPrefix (我正在使用nuget包)。您使用tt.transfers的方法是正确的,但是您需要指定的前缀。

而不是仅仅

代码语言:javascript
复制
Html.BeginCollectionItem("tt.transfers")

您还需要当前payment_method的前缀。

代码语言:javascript
复制
@{
    var paymentMethodPrefix = ViewData.TemplateInfo.HtmlFieldPrefix;
}
@using (Html.BeginCollectionItem(paymentMethodPrefix + ".tt.transfers"))

一个快速的测试看起来也可以:

代码语言:javascript
复制
@using (Html.BeginCollectionItem(ViewData.TemplateInfo.HtmlFieldPrefix + ".tt.transfers"))
票数 17
EN

Stack Overflow用户

发布于 2020-01-16 12:57:10

我无法用MVC 5正确地适应just的方法。

代码语言:javascript
复制
public static class HtmlPrefixScopeExtensions
{
    private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";

    public static IDisposable BeginCollectionItem2(this HtmlHelper html, string collectionName)
    {
        if (html.ViewData["ContainerPrefix"] != null)
        {
            collectionName = string.Concat(html.ViewData["ContainerPrefix"], ".", collectionName);
        }

        var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
        string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();

        var htmlFieldPrefix = string.Format("{0}[{1}]", collectionName, itemIndex);

        html.ViewData["ContainerPrefix"] = htmlFieldPrefix;

        // autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
        html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));

        return BeginHtmlFieldPrefixScope(html, htmlFieldPrefix);
    }

    public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
    {
        return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
    }

    private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName)
    {
        // We need to use the same sequence of IDs following a server-side validation failure,  
        // otherwise the framework won't render the validation error messages next to each item.
        string key = idsToReuseKey + collectionName;
        var queue = (Queue<string>)httpContext.Items[key];
        if (queue == null)
        {
            httpContext.Items[key] = queue = new Queue<string>();
            var previouslyUsedIds = httpContext.Request[collectionName + ".index"];
            if (!string.IsNullOrEmpty(previouslyUsedIds))
                foreach (string previouslyUsedId in previouslyUsedIds.Split(','))
                    queue.Enqueue(previouslyUsedId);
        }
        return queue;
    }

    private class HtmlFieldPrefixScope : IDisposable
    {
        private readonly TemplateInfo templateInfo;
        private readonly string previousHtmlFieldPrefix;

        public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
        {
            this.templateInfo = templateInfo;

            previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
            templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
        }

        public void Dispose()
        {
            templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
        }
    }
}

脚本如下:

代码语言:javascript
复制
function addRow() {

        $.ajax({
            type: "POST",
            data: {processTypeId:@Model.Id},
            url: '@Url.Action("GetFlowItemRow", "Flow")',
            success: function (partialView) {
                $('#divItemList').append(partialView);
            }
        });
    }

 function addParameterRow(rw, prx) {

        $.ajax({
            type: "POST",
            url: '@Url.Action("GetFlowItemParameterRow", "Flow")' + '?pId=' + '@Model.Id' + '&prefix=' + prx ,
            success: function (partialView) {
                rw.closest('table').find("tbody").append(partialView);
            }
        });
    }

添加部分视图的html按钮,如:

代码语言:javascript
复制
<a title="Add Operation" href="javascript:;" onclick="addRow()">
 <i class="la la-plus-circle"></i>
</a>
<a title="Add Operation Parameter" href="javascript:;" onclick="addParameterRow($(this),'@ViewData["ContainerPrefix"]')">
 <i class="la la-plus-circle"></i>
</a>

控制器的部分视图方法:

代码语言:javascript
复制
public PartialViewResult GetFlowItemRow(int? processTypeId)
    {
        FlowItemModel _item = new FlowItemModel() { ProcessTypeId = processTypeId ?? 0 };
        return PartialView("~/Views/Flow/Partial/_FlowItem.cshtml", _item);
    }

    public PartialViewResult GetFlowItemParameterRow(int? pId, string prefix)
    {
        ViewData["ContainerPrefix"] = prefix;
        FlowItemParameterModel _item = new FlowItemParameterModel() { };

        return PartialView("~/Views/Flow/Partial/_FlowItemParameter.cshtml", _item);
    }

流动项目部分:

代码语言:javascript
复制
<tr>
        @using (Html.BeginCollectionItem2("OperationList"))
        {
            @Html.HiddenFor(model => model.ItemId)
            <td style="vertical-align:middle">
                @Html.TextBoxFor(m => m.Name, new { @class = "form-control" })
            </td>
            <td>
                <table style="width:100%">
                    <thead>
                        <tr>
                            <th class="kt-font-success">Name</th>
                            <th class="kt-font-success">Unit</th>

                            <th>
                                <a title="Add Parameter" href="javascript:;" onclick="addParameterRow($(this),'@ViewData["ContainerPrefix"]')">Add                                        
                                </a>
                            </th>
                        </tr>
                    </thead>
                    <tbody id="divParameterList">


                    </tbody>

                </table>

            </td>                
        }       
</tr>

项目参数部分

代码语言:javascript
复制
<tr>
    @using (Html.BeginCollectionItem2("ParameterList"))
    {

        <td>@Html.TextBoxFor(m => m.ParameterName, new { @class = "form-control" })</td>
        <td>
            @Html.TextBoxFor(m => m.Unit, new { @class = "form-control" })
        </td>                                                
    }</tr>
票数 3
EN

Stack Overflow用户

发布于 2020-08-04 17:16:48

您可以使用JonK答案中的代码,但是它不能用于动态添加来自ajax调用的部分,因为"ViewData.TemplateInfo.HtmlFieldPrefix“是空的。

解决方案是在模型中添加一个带有表单前缀的属性,并填充ajax函数调用的操作。

要使用jQuery获取表单前缀,只需执行以下操作:

代码语言:javascript
复制
// "this" a button that will trigger the ajax call and is within the div with the class "partial-enclosing-class"
var parentRow = $(this).parents('.partial-enclosing-class');
var hiddenInput = parentRow.find('input[name$="].Id"]');
var formPrefix = hiddenInput.prop('name').replace(".Id", "");
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9575732

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档