2015-01-23 4 views
1

Я использую Ajax.BeginForm внутри цикла For Loop, позволяя мне отправлять сообщения в контроллер для каждого элемента цикла for. Изначально цикл for отображает каждый элемент правильно при загрузке страницы. Когда контроллер обработал входящую модель просмотра, которая правильно заполнена из Ajax.BeginForm, метод отправляет обратно созданную модель представления обратно в представление, однако каждый элемент в моем цикле For теперь дублируется, и теперь все текстовые поля имеют значение представленной модели просмотра.MVC Ajax Form in a For Loop

Очень смутно, как правильно структурировать этот код, мне нужно подчинение для работы на основе ajax и частичного представления. Я действительно рассматривал использование JQuery для отправки, но был обеспокоен тем, что я могу потерять AntiForgeryToken и что Ajax.BeginForm был более элегантным. Любая помощь очень ценится. Рад предоставить дополнительную информацию.

VIEW

@model Namespace.Models.MyParentViewModel 
@for (int i = 0; i < Model.Items.Count; i++) 
{ 
    using (Ajax.BeginForm("SaveItem", "Controller", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "pensions" })) 
    { 
     @Html.AntiForgeryToken() 
     @Html.ValidationSummary() 
     <div> 
     @Html.Hidden("ID", Model.Items[i].ID) 
     @Html.TextBox("TheName", Model.Items[i].TheName, new { @class = "form-control", @id = "item-" + i}) 
     <input type="submit" value="Save" class="btn save" name="Command" /> 
     </div> 
    } 
} 

CONTROLLER

[HttpPost] 
[ValidateAntiForgeryToken] 
[ActionName("SaveItem")] 
public ActionResult SaveItem(MyItemViewModel mivm, string Command) 
{ 
    if (ModelState.IsValid) 
    { 
     #do some logic 
    } 

    // Return a newly populated MyViewModel with updated mivm. 
    var model = PopulateMyParentViewModel(); 
    return PartialView("_MyPartialView", model); 
} 

private MyParentViewModel PopulateMyParentViewModel() 
{ 
    List<MyItemsViewModel> lstItems = new List<MyItemsViewModel>(); 
    foreach (var item in enity.items.OrderBy(p => p.ID).ToList()) 
    { 
    var ExistingItem = new MyItemViewModel 
    { 
     ID = item.ID, 
     TheName = item.TheName 
    }; 

    lstItems.Add(MyItemViewModel); 
    } 
    MyParentViewModel.Items = lstItems; 
    return MyParentViewModel 
} 

ответ

1

Я не уверен, что "пенсии" в вашем коде, я предполагаю, что это ДИВ окружающий каждую форму, образованную петлю ? Если это так, ваша проблема следующая:

  • Во-первых, если ни один из элементов не связаны между собой (то есть, вызывая некоторое обновление на элементе вызывает еще один пункт для обновления, а), вы не должны тратить ресурсы чтобы отправить весь список обратно в браузер - подумайте о том, чтобы просто отправить обратно обновленное отображение затронутой «записи» и просто обновить соответствующий элемент с ответом.

  • Что вызывает вопросы, которые будут дублироваться: AjaxOptions класса имеет свойство InsertionMode, и я помню, его значение по умолчанию InsertionMode = InsertionMode.InsertAfter, что приводит к дубликатам появляться. Зачем? Вы отправляете на сервер запрос Ajax, который отправляет обратно фрагмент HTML, заполненный всем списком, вместо одного элемента, тогда браузер добавляет этот фрагмент к существующим записям.

Решение

  • Если вы переделать свой проект просто отправить обратно одну запись, а не все из них, просто добавьте однозначно идентифицирован (= имеет уникальный id атрибут) <div> элемент вокруг блока using(...), установите InsertionMode на InsertionMode=InsertionMode.Replace и установите UpdateTargetId на id этого <div>, например:

    <div id="[email protected]">  
    @using (Ajax.BeginForm("SaveItem", "Controller", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "record-" + i.ToString(), InsertionMode = InsertionMode.Replace })) 
    { 
        // ... 
    } 
    </div> 
    

    Это вызовет отклик Ajax заменить содержимого контейнера, с которого отправляется запрос (по содержания Я имею в виду, что сама упаковка элемент не будет заменен! Для этого вам нужно использовать InsertionMode.ReplaceWith). Если вы допустили ошибку, вы в конечном итоге сбросили сумасшедшие количества вложенных элементов внутри контейнера-хоста, возможно, нарушив скрипты и/или стили, которые используют очень специфические селектора.

  • Если вы будете придерживаться отправок целой коллекции элементов обратно, а затем просто обернуть цикл с <div> тегом, дать ему id, установите InsertionMode в InsertionMode=InsertionMode.Replace и UpdateTargetId собственности на id этого <div>.

--------- Обновление -----------

Чтобы ответить на ваш комментарий:

Предположим, у вас есть представление, которое - для ради простоты - отображает записи в табличном формате. Затем, результат выглядит следующим образом:

Name | Age | Salary | Hide 
------------------------------------ 
Peter | 32 | $15k | Hide button 
Eva | 28 | $12k | Hide button 

Предположим, что вы изменить с просьбой Ajax является то, что всякий раз, когда вы скрываете запись, вы посылаете назад один строку таблицы с кнопкой, которая теперь отображает «шоу» вместо " hide 'и те же данные о человеке, который принадлежит кнопке, вызвавшей запрос. Затем, когда вы делаете запрос на прямой (= не Аякса, когда вы непосредственно перейти к странице), вы делаете это:

@model PeopleCollection 
... 
<table> 
<thead> 
    <tr> 
    <td>Name</td> 
    <td>Age</td> 
    <td>Salary</td> 
    <td>Hide</td> 
    </tr> 
</thead> 
<tbody> 
    @foreach (Person record in Model) { 
    @Html.Partial("TableRow_Partial",record) 
    } 
</tbody> 

Вид «TableRow_Partial» выглядит следующим образом:

@model Person 
@{ 
    AjaxOptions opts = new AjaxOptions() { 
    UpdateTargetId = "person-row-" + Model.Id.ToString(), 
    InsertionMode = InsertionMode.ReplaceWith 
    // etc 
    }; 
} 
... 
<tr id="[email protected]"> 
    <td>@Model.Name</td> 
    <td>@Model.Age</td> 
    <td>@Model.Salary</td> 
    <td> 
    <!-- configure the BeginForm(..) call with the action name and a routeValue anonymous object as "new { id = Model.Id}" --> 
    @using (Ajax.BeginForm(...)) { 
     <input type="submit" value="@(Model.IsHidden ? "Show" : "Hide")" /> 
    } 
    </td> 
</tr> 

Это просто извлечет конструкцию петель в отдельный частичный вид. Процессия метода действия вашего Ajax-запрос будет просто возвращать эту точку зрения, наполненная одной записи, которую вы обновили, например, так:

public ActionResult UpdateRecord(Int64 id) 
{ 
    var _record = Repository.Get(id); 
    // logic to hide and update record 
    return PartialView("TableRow_Partial",_record); 
} 

Для этого, чтобы работать, вы должны установить InsertionMode в InsertionMode.ReplaceWith. Все, что вы делаете, заключается в том, что когда вы отправляете запрос ajax, чтобы сделать что-то только с одной записью, вы обновляете только один элемент - тот, который вызвал вызов ajax, а затем вы просто возвращаете новую строку (одну строку!) И заменяете старый один с этим новым.

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

+0

Спасибо, но немного смущен возвратной моделью. Если я использую код из вашего решения, я могу передать одну модель контроллеру и обновить эту модель в базе данных, но по мере того, как контроллер вернет список элементов, этот список затем заменит одну строку в записи - @ i будет весь список , используемый для итерации цикла For, и все равно приведет к дублированию. «Пенсии» на самом деле являлись обертыванием всего частичного представления этого цикла. – Richter84

+0

Ответ обновлен. –

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

  • Нет связанных вопросов^_^