2013-11-21 2 views
3

У меня очень большая форма в моем приложении с множеством разных входов и множеством списков в моей модели. Поэтому я попытаюсь добавить/удалить списки без отправки полной модели на сервер.Связать динамически созданный элемент с сложной моделью mvc in view

Я пробовал несколько способов, но я не нашел чистого пути. Вы можете представить себе мою модель:

public class EditSomething 
{ 
    public string name { get; set;} 

    public List<something> somethingList { get; set;} 

    // a lot other fields... 

    public EditSomething(EditSomethingFromDatabase editSomethingFromDatabase) 
    { 
     name = editSomethingFromDatabase.Name; 
     somethingList = new List<SomethingModel>(); 
     foreach(var something in editSomethingFromDatabase.Something) 
     { 
      somethingList.Add(new SomethingModel(editSomethingFromDatabase.Something)); 
     } 
    } 
} 

Другая модель выглядит аналогично, но без списков.

В представлении У меня есть таблица для модели:

<h2>Something</h2> 
    <div id="SomethingDiv"> 
     <table id="SomethingTable"> 
      <thead> 
       <tr> 
        <th>@Html.Label("SomethingName")</th> 
        <th>@Html.Label("SomethingID")</th> 
               <th></th> 
       </tr> 
      </thead> 
      <tbody id="SomethingTableBody"> 

       @Html.EditorFor(x => x.somethingList) 

      </tbody> 
     </table> 
     <p> 
      <input type="button" name="addSomething" value="Add Something" id="AddSomething"> 
     </p> 
    </div> 

JQuery из addSomething является: метод

$('#AddSomething').click(function() { 
     $.ajax({ 
      url: '@Url.Action("AddSomething", "SomethingModels")', 
      data: { tableSize: $('#SomethingTable tr').length }, 
      cache: false, 
      success: function (html) { $('#SomethingTable tr:last').after(html); } 
     }); 

Контроллер AddSomething является:

public ActionResult AddSomething (int tableSize) 
{ 
    SomethingModel something= new SomethingModel(null, (-2) * (tableSize + 1)); 
    return PartialView(""~/Views/EditorTemplates/EditSomethingModel.cshtml"", something); 
} 

И по крайней мере, у меня есть редакторский шаблон в EditorTemplates, как и для редактора и частичного просмотра. Это имеет важные информации я хочу, чтобы отправить на сервер:

@model SomethingModel 
<tr>@TextBoxFor(m=>m.SomethingName)<td> 

@TextBoxFor (м => m.SomethingID)

Итак, проблема теперь в том, что представить на первый взгляд только после SomethingModel на сервере, который уже существовал при открытии представления, но новый SomethingModel из метода AddMutation не был в сообщении. У кого-то есть идея исправить это?

Редактировать: Изменен путь к шаблону редактора, поэтому мне нужен только один вид для EditorFor и PartialView.

Редактировать 2: Чтобы решить основную проблему, я создал представление как следующее и использую его как частичный вид. Теперь данные отправляются на сервер правильно. Только проверка на стороне клиента по-прежнему не работает:

@model SomethingModel 
    <tr>@TextBoxFor(m=>m.SomethingName, new{Name="somethingList["+ViewBag.ListId+"].SomethingName")<span class="field-validation-valid" data-valmsg-for="somethingList[@ViewBag.ListId].SomethingName" data-valmsg-replace="true"></span><td> 
<tr>@TextBoxFor(m=>m.SomethingID, new{Name="somethingList["+ViewBag.ListId+"].SomethingID")<span class="field-validation-valid" data-valmsg-for="somethingList[@ViewBag.ListId].SomethingID" data-valmsg-replace="true"></span><td> 
</tr> 

В методе AddSomething я добавил ViewBag.ListId с идентификатором следующего элемента в списке.

+0

Я изменил мой ответ с изменением вам нужно сделать, чтобы получить ненавязчивую проверку на работайте со своими новыми полями после обратного вызова ajax. –

+0

Да, это видно. Но вам нужно удалить все проверки из формы, которую вы хотите отправить. Это будет работать: var table = '$ ('# SomethingForm'). RemoveData (" validator "). RemoveData (" unobtrusiveValidation "); $ .validator.unobtrusive.parse (таблица); 'Большое спасибо –

ответ

2

кажется достаточно разумный подход, но Вы не показали свой EditorTemplate, так что я буду считать, что его что-то вроде:

@model List<something> 

@for(int i = 0; i < Model.Count; i++) 
{ 
    <tr> 
    <td>@Html.DisplayFor(m => m[i].Id) @Html.HiddenFor(m => m[i].Id)</td> 
    <td>@Html.EditorFor(m => m[i].Name)</td> 
    </tr> 
} 

Ваш метод Аякса должен возвращать HTML-строки - и это важно ... поля формы должны быть названы 1 выше последнего в таблице.

Итак, когда вы просматриваете обработанную источник вашей таблицы (перед добавлением новых полей может выглядеть следующим образом:

... 
<tbody> 
    <tr> 
    <td>1 <input type="hidden" name="something[0].Id" value="1"/></td> 
    <td><input type="text" name="something[0].Name" value="somename" /></td> 
    </tr> 
</tbody> 

Вы должны убедиться, HTML, возвращенное методом Ajax для новой строки:

<tr> 
    <td>2 <input type="hidden" name="something[1].Id" value="2"/></td> 
    <td><input type="text" name="something[1].Name" value="somenewname" /></td> 
    </tr> 

т.е.. число в скобках является следующим индексом для элементов в чем-то. Если есть разрыв в индексах (или они перекрывают друг друга), то новые элементы не будут разобраны.

EDIT - получить подтверждение на стороне клиента, чтобы работать на новые поля изменяют свой JQuery Ajax успеха обратного вызова следующим образом:

$('#AddSomething').click(function() { 
    $.ajax({ 
     url: '@Url.Action("AddSomething", "SomethingModels")', 
     data: { tableSize: $('#SomethingTable tr').length }, 
     cache: false, 
     success: function (html) { 
      $('#SomethingTable tr:last').after(html); 
      $.validator.unobtrusive.parse('#SomethingTable'); 
     } 
    }); 
+0

Я изменил код в своем вопросе. Последний образец кода - это шаблон редактора. Я использую 'EditorFor', чтобы показать каждый элемент из somethingList. Помощник mvc автоматически разбивал viw для каждого элемента в списке, поэтому вам не нужно использовать цикл. Также мой метод ajax вернул HTML строки, но ваше право не использует нумерацию из списка. Вместо '' i только создаю его как ' '. Так что спасибо за это, я проверю, как я могу это изменить. –

+0

@James, если у вас есть пробел в индексах, скажем, потому что у вас есть минусовая кнопка для удаления динамического html, как я могу разобрать всю коллекцию? – Zinov

+0

@ Zinov Вам понадобится javascript для переиндексации всех полей позже, чем удаленный. Вы не можете оставлять пробелы в индексах на стороне клиента или они не будут разбираться при обратной передаче. Например, '', а затем определить функцию javascript, которая удаляет строку, и проходит через набор строк с более высоким индексом - заменяя все экземпляры [rowindex] с [rowindex -1] –

Смежные вопросы