2011-12-19 6 views
5

Sto usando l'helper BeginCollectionItem di Steve Sanderson e ho riscontrato un problema. Ho un modulo che ha un'opzione per aggiungere campi premio illimitati. Sto usando il suo helper poiché ha risolto questo problema con come continuare a generare i campi e non doversi preoccupare di come associarlo quando il modulo viene inviato.L'helper BeginCollectionItem di Steve Sanderson non si associa correttamente

Ho in questo stesso modulo alcune caselle di controllo che c'è una quantità sconosciuta. La differenza con questa contro le ricompense è che la quantità sconosciuta diventerà nota dopo una chiamata al database e sarà nota al momento in cui il codice arriva alla vista.

Quindi il mio codice è simile

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

Sto usando jQuery per presentare i dati utilizzando serializeArray(). Quando va al server, lega correttamente tutti quelli dinamici e lega anche la Garanzia alla Collezione (il conteggio delle raccolte è 1). Eppure non lega mai nulla all'interno di WarrantyFeaturesVm, tutto è lasciato come predefinito.

se rimuovo utilizzando (Html.BeginCollectionItem("WarrantyFeaturesVm")) quindi non legherà nemmeno la raccolta.

Qualcuno sa perché non è vincolante nulla nella raccolta?

Modifica

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

E le vostre garanzie foreach si trovano all'interno di un Html.BeginForm? Ti dispiacerebbe pubblicare alcuni esempi di output HTML per un insieme di garanzie? – danludwig

+0

Sì, sono in un Html.BeginForm. Penso di averlo capito (parzialmente). Se cambio il ciclo foreach in un forloop, faccio qualcosa come @ Html.TextBoxFor (x => Model.WarrantyFeaturesVm [i] .FeatureId) funziona. Non sono sicuro del motivo per cui startCollection non funziona comunque. – chobo2

+0

Il raccoglitore modello esamina l'HTML. Scopri le differenze nel modo in cui gli ID HTML sono resi in modo diverso nei 2 casi diversi. Utilizziamo spesso foreach con BeginCollectionItem, ma spesso BeginCollectionItem si trova in un modello parziale o editor. – danludwig

risposta

8

Ok mi sembra di vedere che cosa sta succedendo qui.

Nel secondo campione, dove ha fatto il foreach, sembra che il tuo cshtml fosse qualcosa di simile (@ simboli potrebbero non essere corretti):

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

Perché BeginCollectionItem utilizza il suo contesto di ricavare i nomi HTML e id, questo è il motivo per cui finisci con "guerra" in ID e nomi. Il raccoglitore modello sta cercando una proprietà di raccolta denominata "WarrantyFeaturesVm", che trova. Tuttavia, sta cercando una proprietà denominata "war" sul viewmodel WarrantyFeaturesVm, che non è in grado di trovare, e quindi non vincola.

<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" .../> 

Nel 3 ° scenario, è simile. Sta cercando la proprietà della collezione WarranyFeaturesVm, che trova. Tuttavia cerca un altro oggetto da collezione.

<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" .../> 

Al fine di legare in modo corretto, il codice HTML deve essere simile al primo esempio HTML:

<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" .../> 

Come ho accennato nel mio commento, è possibile raggiungere questo obiettivo mettendo il BeginCollectionItem e tutto ciò che avvolge in una vista parziale. La vista parziale riceverà quindi il proprio contesto, dal momento che i tuoi aiutanti useranno la proprietà @Model della vista con gli helper di tipo steso in questo modo: @Html.WidgetFor(m => m.PropertyName).

D'altra parte, se davvero hai bisogno che la collezione sia resa nel vista esterna, non vedo alcun problema usando l'indicizzazione normale (integer-based) con un ciclo for e senza BeginCollectionItem.

Aggiornamento

ho scavato this old post from Phil Haack. Un estratto:

... introducendo un input nascosto aggiuntivo, è possibile consentire arbitrari indici . Nell'esempio seguente, forniamo un input nascosto con il suffisso .Index per ciascun elemento che è necessario associare all'elenco. Il nome di ciascuno di questi ingressi nascosti è lo stesso, così come descritto in precedenza, questo darà al raccoglitore del modello una bella collezione di indici da cercare per il collegamento alla lista.

<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 utilizza questo metodo di indicizzazione per assicurarsi che accada modello vincolante. L'unica differenza è che utilizza Guidi invece di intter come l'indicizzatore. Ma potresti impostare manualmente qualsiasi indicizzatore come nell'esempio di Phil sopra.

+0

Ah. Dovrò provare questo. Ya ho appena usato il metodo basato su interi, ma all'inizio ho pensato che in qualche modo l'aiutante stava effettuando ciò quando in realtà stavo proprio sbagliando lol. – chobo2

+0

BeginCollectionItem non perfetto. Questa è l'unica cosa che mi manca di fare php 10 anni fa. Mi piacerebbe molto se MVC ti lascia passare in raccolte semplicemente usando l'input id = "CollectionProperty []". Sarebbe molto più facile. – danludwig

Problemi correlati