2011-12-19 12 views
5

Tôi đang sử dụng trình trợ giúp BeginCollectionItem của Steve Sanderson và gặp sự cố. Tôi có một biểu mẫu có tùy chọn thêm trường phần thưởng không giới hạn. Tôi đang sử dụng helper của mình vì nó đã giải quyết vấn đề này bằng cách làm thế nào để tiếp tục tạo ra các trường và không phải lo lắng về cách liên kết nó khi biểu mẫu được gửi đi.Trình trợ giúp BeginCollectionItem của Steve Sanderson sẽ không ràng buộc chính xác

Tôi có cùng biểu mẫu này một số hộp kiểm có số lượng không xác định. Sự khác biệt với điều này so với phần thưởng là số tiền không xác định sẽ được biết sau khi có cuộc gọi cơ sở dữ liệu và sẽ được biết đến khi mã được xem.

Vì vậy, mã của tôi trông như thế này

public class FrmVm 
    { 
     public Guid Id { get; set; } 
     public string Name { get; set; } 
     public bool Active { get; set; } 

     public IList<WarrantyFeaturesVm> WarrantyFeaturesVm { get; set; } // this is the checkbox ones. 
     public IList<RewardVms> RewardVms { get; set; } // this is the dyanmic one that I needed the helper for 

     public CbCreditCardFrmVm() 
     { 
      Active = true; 
      WarrantyFeaturesVm = new List<WarrantyFeaturesVm>(); 
      RewardVms = new List<RewardVms>(); 
     } 
    } 


    // view 

    @foreach (var tier in Model.RewardVms) 
    { 
      @Html.Partial("GenerateReward", tier) // in this partial view in the BeginCollectionItem     
    } 



@foreach (var warranties in Model.WarrantyFeaturesVm) 
{ 
    using (Html.BeginCollectionItem("WarrantyFeaturesVm")) 
    { 
     <span>@warranties.Name:</span> 
     @Html.TextBoxFor(x => warranties.FeatureId) 
     @Html.CheckBoxFor(x => warranties.HasFeature) 
    } 
} 

Tôi đang sử dụng jquery để gửi dữ liệu bằng cách sử dụng serializeArray(). Khi nó đi đến máy chủ nó ràng buộc tất cả những người năng động một cách chính xác và thậm chí ràng buộc bảo hành cho bộ sưu tập (số lượng bộ sưu tập là 1). Tuy nhiên, nó không bao giờ liên kết bất cứ điều gì bên trong các WarrantyFeaturesVm, tất cả mọi thứ còn lại như mặc định.

nếu tôi xóa bằng cách sử dụng (Html.BeginCollectionItem("WarrantyFeaturesVm")) thì nó thậm chí sẽ không ràng buộc bộ sưu tập.

Bất kỳ ai biết tại sao nó không ràng buộc bất kỳ thứ gì trong bộ sưu tập?

Sửa

// for loop (works) 
<form method="post" id="" action="" class="ui-formwizard ui-helper-reset ui-widget ui-widget-content ui-corner-all" novalidate="novalidate"> 

<span id="" class="step ui-formwizard-content ui-helper-reset ui-corner-all" style="display: none;"> 

<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191" name="WarrantyFeaturesVm[0].FeatureId" id="WarrantyFeaturesVm_0__FeatureId" data-val-required="The FeatureId field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default"> <span>Purchase</span> 
<input type="checkbox" value="true" name="WarrantyFeaturesVm[0].HasFeature" id="WarrantyFeaturesVm_0__HasFeature" data-val-required="The HasFeature field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default"><input type="hidden" value="false" name="WarrantyFeaturesVm[0].HasFeature" class="ui-wizard-content ui-helper-reset ui-state-default"> 

</form> 




//foreach loop beginItemCollection(does not work) 


<form method="post" id="" action="" class="ui-formwizard ui-helper-reset ui-widget ui-widget-content ui-corner-all" novalidate="novalidate"> 

<span id="" class="step ui-formwizard-content ui-helper-reset ui-corner-all" style="display: inline;"> 

<input type="hidden" value="68ba9241-c409-4f4b-96da-cce13b127c1e" autocomplete="off" name="WarrantyFeaturesVm.index" class="ui-wizard-content ui-helper-reset ui-state-default"> 
<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191" name="WarrantyFeaturesVm[68ba9241-c409-4f4b-96da-cce13b127c1e].war.FeatureId" id="WarrantyFeaturesVm_68ba9241-c409-4f4b-96da-cce13b127c1e__war_FeatureId" data-val-required="The FeatureId field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default">   <span>Purchase</span> 
<input type="checkbox" value="true" name="WarrantyFeaturesVm[68ba9241-c409-4f4b-96da-cce13b127c1e].war.HasFeature" id="WarrantyFeaturesVm_68ba9241-c409-4f4b-96da-cce13b127c1e__war_HasFeature" data-val-required="The HasFeature field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default"><input type="hidden" value="false" name="WarrantyFeaturesVm[68ba9241-c409-4f4b-96da-cce13b127c1e].war.HasFeature" class="ui-wizard-content ui-helper-reset ui-state-default"> 

</span> 

</form> 





//for loop beginItemCollection (does not work) 
<form method="post" id="" action="" class="ui-formwizard ui-helper-reset ui-widget ui-widget-content ui-corner-all" novalidate="novalidate"> 


<span id="" class="step ui-formwizard-content ui-helper-reset ui-corner-all" style="display: none;"> 

<input type="hidden" value="fe3fbc82-a2df-476d-a15a-dacd841df97e" autocomplete="off" name="WarrantyFeaturesVm.index" class="ui-wizard-content ui-helper-reset ui-state-default"> 
<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191" name="WarrantyFeaturesVm[fe3fbc82-a2df-476d-a15a-dacd841df97e].WarrantyFeaturesVm[0].FeatureId" id="WarrantyFeaturesVm_fe3fbc82-a2df-476d-a15a-dacd841df97e__WarrantyFeaturesVm_0__FeatureId" data-val-required="The FeatureId field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default">   <span>Purchase</span> 
<input type="checkbox" value="true" name="WarrantyFeaturesVm[fe3fbc82-a2df-476d-a15a-dacd841df97e].WarrantyFeaturesVm[0].HasFeature" id="WarrantyFeaturesVm_fe3fbc82-a2df-476d-a15a-dacd841df97e__WarrantyFeaturesVm_0__HasFeature" data-val-required="The HasFeature field is required." data-val="true" class="ui-wizard-content ui-helper-reset ui-state-default"><input type="hidden" value="false" name="WarrantyFeaturesVm[fe3fbc82-a2df-476d-a15a-dacd841df97e].WarrantyFeaturesVm[0].HasFeature" class="ui-wizard-content ui-helper-reset ui-state-default"> 

</span> 

<span id="adminSettings" class="step ui-formwizard-content ui-helper-reset ui-corner-all" style="display: inline;"> 

</form> 
+0

Và bảo hành foreach của bạn nằm trong Html.BeginForm? Bạn có nhớ đăng một số đầu ra HTML mẫu cho một bộ bảo đảm không? – danludwig

+0

Có họ đang ở trong một Html.BeginForm. Tôi nghĩ tôi đã tìm ra (một phần). Nếu tôi thay đổi vòng lặp foreach thành một forloop thì hãy làm một cái gì đó như @ Html.TextBoxFor (x => Model.WarrantyFeaturesVm [i] .FeatureId) nó hoạt động. Bạn không chắc chắn lý do startCollection không hoạt động. – chobo2

+0

Trình kết nối mô hình xem xét HTML. Kiểm tra sự khác biệt về cách các id HTML được hiển thị khác nhau trong 2 trường hợp khác nhau. Chúng tôi thường xuyên sử dụng foreachCollectionItem, nhưng thường BeginCollectionItem nằm trong một phần mẫu hoặc trình soạn thảo. – danludwig

Trả lời

8

Ok Tôi nghĩ rằng tôi nhìn thấy những gì đang xảy ra ở đây.

Trong mẫu thứ hai, nơi bạn đã foreach, nó trông giống như cshtml của bạn là một cái gì đó như thế này (@ những biểu tượng có thể không đúng):

foreach (var war in Model.WarrantyFeaturesVm) { 
    using (Html.BeginCollectionItem("WarrantyFeaturesVm")) { 
     Html.HiddenFor(m => war.FeatureId) 
     <span>@Html.DisplayFor(m => war.Name)</span> 
     Html.HiddenFor(m => war.HasFeature) 
    } 
} 

Vì BeginCollectionItem sử dụng ngữ cảnh của nó để lấy được tên HTML và id, đây là lý do tại sao bạn kết thúc với "chiến tranh" trong id và tên. Trình kết nối mô hình đang tìm kiếm một thuộc tính bộ sưu tập có tên là "WarrantyFeaturesVm", mà nó tìm thấy. Tuy nhiên, sau đó nó tìm kiếm một thuộc tính có tên "war" trên khung nhìn SecurityFeaturesVm viewmodel, mà nó không thể tìm thấy, và do đó không ràng buộc.

<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191" 
    name="WarrantyFeaturesVm[68ba9241-c409-4f4b-96da-cce13b127c1e].war.FeatureId" 
    id="WarrantyFeaturesVm_68ba9241-c409-4f4b-96da-cce13b127c1e__war_FeatureId" .../> 

Trong trường hợp thứ 3, tương tự. Nó đang tìm kiếm các tài sản thu thập WarranyFeaturesVm, mà nó tìm thấy. Tuy nhiên nó tìm kiếm một mục bộ sưu tập khác.

<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191" 
    name="WarrantyFeaturesVm[fe3fbc82-a2df-476d-a15a-dacd841df97e].WarrantyFeaturesVm[0].FeatureId" 
    id="WarrantyFeaturesVm_fe3fbc82-a2df-476d-a15a-dacd841df97e__WarrantyFeaturesVm_0__FeatureId" .../> 

Để ràng buộc một cách chính xác, HTML bạn phải tìm kiếm tương tự như lần đầu tiên ví dụ HTML của bạn:

<input type="hidden" value="68ba9241-c409-4f4b-96da-cce13b127c1e" 
    name="WarrantyFeaturesVm.index" .../> 
<input type="hidden" value="6aa20677-d367-4e2a-84f0-9fbe00deb191" 
    name="WarrantyFeaturesVm[68ba9241-c409-4f4b-96da-cce13b127c1e].FeatureId" 
    id="WarrantyFeaturesVm_68ba9241-c409-4f4b-96da-cce13b127c1e__FeatureId" .../> 

Giống như tôi đã gợi ý trong nhận xét của tôi, bạn có thể đạt được điều này bằng cách đặt BeginCollectionItem và tất cả mọi thứ nó kết thúc tốt đẹp thành một phần xem. Khi đó, chế độ xem một phần sẽ nhận được bối cảnh của riêng nó, vì người trợ giúp của bạn sẽ sử dụng thuộc tính @Model của chế độ xem với những người trợ giúp có kiểu gõ như vậy: @Html.WidgetFor(m => m.PropertyName).

Mặt khác, nếu bạn thực sự cần bộ sưu tập được hiển thị trong bên ngoài xem, tôi không thấy bất kỳ vấn đề bằng cách sử dụng chỉ mục bình thường (số nguyên dựa trên) với một vòng lặp for và không có BeginCollectionItem.

Cập nhật

tôi đào lên this old post from Phil Haack. Đoạn trích:

... bằng cách giới thiệu thêm đầu vào bị ẩn, bạn có thể cho phép tùy ý chỉ mục. Trong ví dụ bên dưới, chúng tôi cung cấp đầu vào bị ẩn với hậu tố của mỗi mục chúng tôi cần để liên kết với danh sách. Tên của mỗi đầu vào bị ẩn này giống nhau, như được mô tả trước đó, điều này sẽ cung cấp cho mô hình kết hợp một bộ sưu tập các chỉ mục tốt đẹp để xem khi liên kết với danh sách.

<form method="post" action="/Home/Create"> 

    <input type="hidden" name="products.Index" value="cold" /> 
    <input type="text" name="products[cold].Name" value="Beer" /> 
    <input type="text" name="products[cold].Price" value="7.32" /> 

    <input type="hidden" name="products.Index" value="123" /> 
    <input type="text" name="products[123].Name" value="Chips" /> 
    <input type="text" name="products[123].Price" value="2.23" /> 

    <input type="hidden" name="products.Index" value="caliente" /> 
    <input type="text" name="products[caliente].Name" value="Salsa" /> 
    <input type="text" name="products[caliente].Price" value="1.23" /> 

    <input type="submit" /> 
</form> 

BeginCollectionItem sử dụng phương pháp lập chỉ mục này để đảm bảo mô hình ràng buộc xảy ra. Sự khác biệt duy nhất là nó sử dụng Guids thay vì ints như là indexer. Nhưng bạn có thể tự đặt bất kỳ chỉ mục nào như trong ví dụ của Phil ở trên.

+0

Ah. Tôi sẽ phải thử cái này. Ya, tôi sẽ sử dụng số nguyên dựa trên cách nhưng tôi nghĩ lúc đầu rằng bằng cách nào đó helper đã được thực hiện rằng khi thực sự tôi đã chỉ làm điều đó sai lol. – chobo2

+0

BeginCollectionItem không hoàn hảo. Đây là điều duy nhất tôi bỏ lỡ khi làm php 10 năm trước. Tôi rất thích nó nếu MVC cho phép bạn vượt qua trong bộ sưu tập chỉ đơn giản bằng cách sử dụng id đầu vào = "CollectionProperty []". Sẽ dễ dàng hơn nhiều. – danludwig