2015-01-19 6 views
18

Dodałem przycisk w moim widoku. Po kliknięciu tego przycisku dodawany jest widok częściowy. W mojej formie mogę dodać tyle częściowego widoku, ile mogę. Przesyłając dane tego formularza, nie mogę wysłać wszystkich danych widoku częściowego do kontrolera. Zrobiłem inny model posiadający wszystkie atrybuty i sporządziłem listę tego modelu do mojego głównego modelu. Czy ktokolwiek może mi podać jakąś sztuczkę, abym mógł przesłać całą zawartość widoku częściowego do kontrolera?Prześlij ten sam widok częściowy o nazwie wiele razy do kontrolera?

moim zdaniem

<div id="CSQGroup"> 
</div> 
<div> 
    <input type="button" value="Add Field" id="addField" onclick="addFieldss()" /> 
</div> 

function addFieldss() 
{  
    $.ajax({ 
    url: '@Url.Content("~/AdminProduct/GetColorSizeQty")', 
    type: 'GET', 
    success:function(result) { 
     var newDiv = $(document.createElement("div")).attr("id", 'CSQ' + myCounter); 
     newDiv.html(result); 
     newDiv.appendTo("#CSQGroup"); 
     myCounter++; 
    }, 
    error: function(result) { 
     alert("Failure"); 
    } 
    }); 
} 

w moim kontrolera

public ActionResult GetColorSizeQty() 
{ 
    var data = new AdminProductDetailModel(); 
    data.colorList = commonCore.getallTypeofList("color"); 
    data.sizeList = commonCore.getallTypeofList("size"); 
    return PartialView(data); 
} 

[HttpPost] 
public ActionResult AddDetail(AdminProductDetailModel model) 
{ 
    .... 
} 

W moim częściowym widokiem

@model IKLE.Model.ProductModel.AdminProductDetailModel 
<div class="editor-field"> 
    @Html.LabelFor(model => model.fkConfigChoiceCategorySizeId) 
    @Html.DropDownListFor(model => model.fkConfigChoiceCategorySizeId, Model.sizeList, "--Select Size--") 
    @Html.ValidationMessageFor(model => model.fkConfigChoiceCategorySizeId) 
</div> 
<div class="editor-field"> 
    @Html.LabelFor(model => model.fkConfigChoiceCategoryColorId) 
    @Html.DropDownListFor(model => model.fkConfigChoiceCategoryColorId, Model.colorList, "--Select Color--") 
    @Html.ValidationMessageFor(model => model.fkConfigChoiceCategoryColorId) 
</div> 
<div class="editor-field"> 
    @Html.LabelFor(model => model.productTotalQuantity) 
    @Html.TextBoxFor(model => model.productTotalQuantity) 
    @Html.ValidationMessageFor(model => model.productTotalQuantity) 
</div> 
+0

Pokaż swój kod! –

+0

Proszę przejrzeć kod i jeśli potrzebujesz więcej informacji, proszę o kontakt. – Brajesh

+0

Co to jest metoda POST dla formularza? Wspomniałeś o kolekcji, ale widok częściowy generowania nie będzie wracał do kolekcji (atrybuty nazwy nie zawierają indeksów do wiązania z kolekcją) –

Odpowiedz

46

Twój problem jest, że częściowe renderuje html na podstawie pojedynczego AdminProductDetailModel obiektu, mimo to próbujesz przywrócić kolekcję. Gdy dynamicznie dodajesz nowy obiekt, kontynuujesz dodawanie zduplikowanych formantów, które wyglądają jak <input name="productTotalQuantity" ..> (to także tworzy nieprawidłowy html ze względu na zduplikowane atrybuty id), gdzie muszą być <input name="[0].productTotalQuantity" ..>, <input name="[1].productTotalQuantity" ..> itd. W celu powiązania z kolekcją odeślij z powrotem.

The DefaultModelBinder wymagany że indekser przedmiotów zbiórki zaczynają się od zera i być kolejne, albo że wartości forma obejmują Index=someValue gdzie indekser jest someValue (np <input name="[ABC].productTotalQuantity" ..><input name="Index" value="ABC">. Jest to wyjaśnione szczegółowo w artykule Phil Haack za Model Binding To A List. Używanie podejście Index jest na ogół lepsza, ponieważ pozwala także na usunięcie pozycji z listy (w przeciwnym razie należałoby zmienić nazwy wszystkich istniejących formantów więc indekser jest konsekutywne).

dwa możliwe podejścia do problemu.

Opcja 1

Użyj pomocnika BeginItemCollection dla widoku częściowego. Ten pomocnik wyrenderuje ukryte dane wejściowe dla wartości Index na podstawie identyfikatora GUID. Potrzebujesz tego zarówno w częściowym widoku, jak iw pętli, w której renderujesz istniejące elementy. Twój częściowy wyglądałby coś

@model IKLE.Model.ProductModel.AdminProductDetailModel 
@using(Html.BeginCollectionItem()) 
{ 
    <div class="editor-field"> 
    @Html.LabelFor(model => model.fkConfigChoiceCategorySizeId) 
    @Html.DropDownListFor(model => model.fkConfigChoiceCategorySizeId, Model.sizeList, "--Select Size--") 
    @Html.ValidationMessageFor(model => model.fkConfigChoiceCategorySizeId) 
    </div> 
    .... 
} 

opcja 2

ręcznie utworzyć elementy HTML reprezentujące nowy obiekt z „fałszywych” indekser, umieść je w ukrytym pojemnika, a następnie w razie przycisk Dodaj , sklonuj html, zaktualizuj indeksy i wartość indeksu i dołącz sklonowane elementy do DOM. Aby upewnić się, że html jest poprawny, utwórz jeden domyślny obiekt w pętli for i sprawdź wygenerowany kod HTML. Przykładem takiego podejścia jest pokazany w this answer

<div id="newItem" style="display:none"> 

    <div class="editor-field"> 
    <label for="_#__productTotalQuantity">Quantity</label> 
    <input type="text" id="_#__productTotalQuantity" name="[#].productTotalQuantity" value /> 
    .... 
    </div> 
    // more properties of your model 
</div> 

Uwaga Użycie o „fałszywej” indekser aby zapobiec tego jednego wiążąc na post z powrotem („#” i „%” przyzwyczajenie dopasować tak są one ignorowane przez DefaultModelBinder)

$('#addField').click(function() { 
    var index = (new Date()).getTime(); 
    var clone = $('#NewItem').clone(); 
    // Update the indexer and Index value of the clone 
    clone.html($(clone).html().replace(/\[#\]/g, '[' + index + ']')); 
    clone.html($(clone).html().replace(/"%"/g, '"' + index + '"')); 
    $('#yourContainer').append(clone.html()); 
} 

zaletą wariantu 1 jest to, że są silnie wpisując widok na modelu, ale oznacza to wykonanie połączenia do serwera przy każdym dodaniu nowego elementu.Zaletą opcji 2 jest to, że jest ona wykonana po stronie klienta, ale w przypadku wprowadzenia zmian w modelu (np. Dodanie atrybutu sprawdzania poprawności do właściwości), należy również ręcznie zaktualizować kod HTML, co spowoduje, że konserwacja będzie nieco trudniejsza.

Wreszcie, jeśli używasz sprawdzania poprawności strony klienta (jquery-validate-unobtrusive.js), musisz ponownie przeanalizować weryfikator za każdym razem, gdy dodajesz nowe elementy do modelu DOM, jak wyjaśniono w this answer.

$('form').data('validator', null); 
$.validator.unobtrusive.parse($('form')); 

I oczywiście trzeba zmienić piszesz metodę przyjąć zbiór

[HttpPost] 
public ActionResult AddDetail(IEnumerable<AdminProductDetailModel> model) 
{ 
    .... 
} 
+0

Dziękujemy za pomoc, ale już rozwiązałem ten problem za pomocą techniki, o której wspomniałeś. – Brajesh

+0

ah dzięki. Naprawdę nie doszedłem do punktu, w którym potrzebuję tego, ale z pewnością przyda mi się, kiedy go potrzebuję. ;) – Ian

+0

Każdy, kto tu przyjdzie, gorąco polecam pomocnika BeginItemCollection. To jest jak oszustwo. – Preston