2013-02-11 20 views
54

Jeśli chcę zestaw wejść w postaci, która wiąże się z List w MVC 4, wiem, że po konwencji nazewnictwa dla inputname atrybutów będzie działać:Jak działa powiązanie modelu listy MVC 4?

<input name="[0].Id" type="text" /> 
<input name="[1].Id" type="text" /> 
<input name="[2].Id" type="text" /> 

Ale jestem ciekaw jak przebaczenie model spoiwa to. Na przykład co z następującym:

<input name="[0].Id" type="text" /> 
<input name="[3].Id" type="text" /> 
<input name="[8].Id" type="text" /> 

Jak poradzi sobie z tym model spoiwa? Czy byłby powiązany z List o długości 9 z wartościami zerowymi? A może nadal wiąże się z List o długości 3? A może dusi się w ogóle?

Dlaczego zależy mi

Chcę zaimplementować dynamiczny formularz, w którym użytkownik może dodać wiersze do formy, a także może usunąć wiersze z formularza. Jeśli więc użytkownik usunie wiersz 2 z 8 wierszy całkowitych, chcę się dowiedzieć, czy muszę ponumerować wszystkie kolejne dane wejściowe.

+1

spojrzeć na to: http://stackoverflow.com/questions/ 7807127/nie-sekwencyjne powiązanie list-nie działa. Pytanie pokazuje składnię dla niesekwencyjnego powiązania (a odpowiedź potwierdza jej dostępność w MVC2 i wyższych). Używałem go przy okazji. Co do twojego pierwotnego pytania: jeśli dobrze pamiętam, to się nie powiedzie ... ale łatwo jest spróbować, zanim zawracasz sobie głowę ręcznym indeksowanym, niesekwencyjnym wiązaniem. –

+1

@TimMedora, Dzięki - niesekwencyjne powiązanie było pomocne w terminologii, której mi brakowało. – Eric

+4

Temat jest zaskakująco mało znany. Jeśli przeszukujesz wokół, jest kilka dobrych blogów na ten temat, a ta książka obejmuje je dobrze w jednym z późniejszych rozdziałów: http://www.amazon.com/PROAS-NET-MVC-3-Framework/dp/1430234040 –

Odpowiedz

45

Nie ma określonego formatu drut do użytku z kolekcji. Jest to omówione na blogu Scotta Hanselman tu:

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

Kolejny wpis na blogu z Phil Haack mówi o tym tutaj:

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

Wreszcie, wpisu na blogu, że robi dokładnie to, co chcesz tutaj :

http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

+0

Doskonała, dzięki – Eric

+4

@shashwat - jak można jednoznacznie odpowiedzieć tak lub nie na pytania otwarte, w których odpowiedź nie może być tak lub nie? –

+1

@AnimalsAreNotOursToEat 'Jak działa powiązanie modelu listy MVC 4?' ** Tak ** – Jonesopolis

3

Mam dynamiczną listę, która wygląda tak:

<ul id="okvedList" class="unstyled span8 editableList"> 
<li> 
    <input data-val="true" data-val-required="The Guid field is required." id="Okveds_0__Guid" name="Okveds[0].Guid" type="hidden" value="2627d99a-1fcd-438e-8109-5705dd0ac7bb"> 
    --//-- 
</li> 

więc kiedy dodać lub usunąć wiersz (elementu Li) muszę zmienić kolejność elementów

this.reorderItems = function() { 
     var li = this.el_list.find('li'); 

     for (var i = 0; i < li.length; i++) { 
      var inputs = $(li[i]).find('input'); 

      $.each(inputs, function() { 
       var input = $(this); 

       var name = input.attr('name'); 
       input.attr('name', name.replace(new RegExp("\\[.*\\]", 'gi'), '[' + i + ']')); 

       var id = input.attr('id'); 
       input.attr('id', id.replace(new RegExp('_.*__', 'i'), '_' + i + '__')); 
      }); 
     } 
    }; 

ta lista umieszczone w prosty Html.BeginFrom od klienta i jak List w parametrze akcji na serwerze

1

Mam również do czynienia z podobnym problemem w przeszłości i używam KnockoutJS do obsługi takiego scenariusza.

Zasadniczo Knockout wysyła kolekcję w łańcuchu JSON, a ja deserializuję je w kontrolerze.

Aby uzyskać więcej informacji: http://learn.knockoutjs.com/#/?tutorial=collections

15

Śledziłem to na Pproach połączono z powyższymi blogami i dodałem kilka szczegółów, które mogą być pomocne dla niektórych - zwłaszcza, że ​​chciałem dynamicznie dodawać dowolną liczbę wierszy, ale nie chciałem używać AJAX, aby to zrobić (chciałem, aby formularz był tylko przesyłany w poście). Nie chciałem też martwić się utrzymywaniem identyfikatorów sekwencyjnych.Byłem przechwytywania listę dat rozpoczęcia i zakończenia:

Zobacz Model:

public class WhenViewModel : BaseViewModel { 
    public List<DateViewModel> Dates { get; set; } 
    //... Other properties 
} 

Start/End Data View Model:

public class DateViewModel { 
    public string DateID { get; set; } 
    public DateTime? StartDate { get; set; } 
    public DateTime? EndDate { get; set; } 
} 

Następnie wykorzystując je na stronie (z datepicker):

<div class="grid-8-12 clear" id="DatesBlock"> 
@{ 
    foreach (DateViewModel d in Model.Dates) { 
     @:<div class="grid-5-12 left clear"> 
      @Html.Hidden("Dates.Index", d.DateID) 
      @Html.Hidden("Dates[" + d.DateID + "].DateID", d.DateID) //ID again to populate the view model 
      @Html.TextBox("Dates[" + d.DateID + "].StartDate", 
          d.StartDate.Value.ToString("yyyy-MM-dd")) 
     @:</div> 
     @:<div class="grid-5-12"> 
      @Html.TextBox("Dates[" + d.DateID + "].EndDate", 
          d.EndDate.Value.ToString("yyyy-MM-dd")) 
     @:</div> 

     <script type="text/javascript"> 
      $('input[name="Dates[@d.DateID].StartDate"]') 
       .datepicker({ dateFormat: 'yy-mm-dd'}); 
      $('input[name="Dates[@d.DateID].EndDate"]') 
       .datepicker({dateFormat: 'yy-mm-dd'}); 
     </script> 
    } 
} 
</div> 
<a href="#" onclick="AddDatesRow()">Add Dates</a> 

Jako że blog opisany w temacie @ErikTheVikings powyżej opisuje, kolekcja jest tworzona przez powtarzający się ukryty element: @Html.Hidden("Dates.Index", d.DateID) dla każdego wpisu w kolekcji na stronie.

Chciałem dowolnie dodawać wierszy bez użycia AJAX w celu wysłania danych do serwera, który zrobiłem tworząc ukryty div zawierający szablon jednego „wiersz”/pozycja w kolekcji:

Ukryte „Template "rząd:

<div id="RowTemplate" style="display: none"> 
    <div class="grid-5-12 clear"> 
     @Html.Hidden("Dates.Index", "REPLACE_ID") 
     @Html.Hidden("Dates[REPLACE_ID].DateID", "REPLACE_ID") 
     @Html.TextBox("Dates[REPLACE_ID].StartDate", "") 
    </div> 
    <div class="grid-5-12"> 
     @Html.TextBox("Dates[REPLACE_ID].EndDate", "") 
    </div> 
</div> 

następnie wykorzystywane jQuery której klony szablonu zapewnia losowy identyfikator do nowego rzędu i dodaje się teraz widoczny sklonowany wiersz zawierającego div powyżej:

jQuery do zakończenia procesu:

<script type="text/javascript"> 
    function AddDatesRow() { 
     var tempIndex = Math.random().toString(36).substr(2, 5); 
     var template = $('#RowTemplate'); 
     var insertRow = template.clone(false); 
     insertRow.find('input').each(function(){ //Run replace on each input 
      this.id = this.id.replace('REPLACE_ID', tempIndex); 
      this.name = this.name.replace('REPLACE_ID', tempIndex); 
      this.value = this.value.replace('REPLACE_ID', tempIndex); 
     }); 
     insertRow.show(); 
     $('#DatesBlock').append(insertRow.contents()); 

     //Attach datepicker to new elements 
     $('input[name="Dates['+tempIndex+'].StartDate"]') 
      .datepicker({dateFormat: 'yy-mm-dd' }); 
     $('input[name="Dates['+tempIndex+'].EndDate"]') 
      .datepicker({dateFormat: 'yy-mm-dd' }); 
    } 
</script> 

JSFiddle przykład w wyniku: http://jsfiddle.net/mdares/7JZh4/

0

Mam mały problem, kiedy i za pomocą przeglądarki Chrome i kliknij przycisk Wstecz, i znaleźć wejście z rodzaju = "ukryty", gdy dynamicznie ustawione wartości nie zostały poprawnie obsłużone przez przeglądarkę Chrome.

może uda nam się zmienić

<input type="hidden" name="Detes.Index" value="2016/01/06" /> 

do

<div style="display: none"> 
    <input type="text" name="Detes.Index" value="2016/01/06" /> 
</div> 

Formularz więcej info: Chrome doesn't cache hidden form field values for use in browser history http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

Powiązane problemy