2012-05-14 1 views
3

Я сделал это в прошлом, и мне, возможно, придется сделать это снова, но прежде чем я это сделаю, я хочу выбросить его туда, чтобы посмотреть, как люди справляются с этим.Как динамически создавать/удалять элементы и разрешать привязку модели к удару?

вид Razor:

<ul> 
    @Html.EditorFor(model => model.Questions) 
</ul> 

Что может производить:

<ul> 
    <li><input type="text" id="Questions_0__Title" name="Questions[0].Title" value="hi"/></li> 
    <li><input type="text" id="Questions_1__Title" name="Questions[1].Title" value="hi2"/></li> 
<ul> 

Довольно мертвую просто.

Теперь, я должен разрешить пользователю добавить, отредактировать или удалить любой из этих «Вопросов».

Для редактирования это легко - без работы. Но для добавления/удаления, если бы я должен был делать это с помощью jQuery, мне нужно было бы быть умным в том, как я генерирую атрибуты «id» и «name» (например, подсчитывайте, сколько их есть, добавьте 1 и т. Д.).), а для удаления я хотел бы «повторно отобразить» некоторые элементы (например, если один был удален, мне нужно будет изменить атрибуты «id» и «name» равными -1 для всех следующих элементов).

Все это потому, что это форма, и она должна быть привязана к модели.

Это для меня слишком волосатый, так в прошлом, я сделал вызов AJAX на сервер с тем, что находится в форме, а затем добавить/удалить элементы в контроллере, и сделать частичный вид. Таким образом, все элементы «готовы к привязке к модели». Мне все еще нужно немного, но jQuery, но нигде не так много.

Кто-нибудь нашел лучший способ?

ответ

-4

Так что я думал о лучшем решении, которое не требует большого количества JS.

  1. В моем контроллере я создаю модель с около 100 элементами.Все пустые, но «новые» и с классом css «скрытые»
  2. Основываясь на количестве существующих значений, я обновляю элементы, в том числе удаляя «скрытый» класс css.
  3. Затем я использую CSS, чтобы скрыть те, у которых есть «скрытый» класс css.
  4. Когда я нажимаю «Добавить больше», я удаляю «скрытый» класс из первых трех элементов.
  5. Когда я нажмите кнопку «Удалить», я просто добавить «скрытый» класс обратно.

Easy, почему я не подумал об этом раньше.

0

Я предполагаю, что эти вещи имеют первичное поле идентификатора ключа?

Не уверен, что это лучший способ, но у меня есть скрытое поле ввода, называемое, например, deletedIds. Оказывая входной элемент добавить атрибут как:

data-rowId='@Model.Id' 

А потом, когда они щелкают удалить добавить идентификатор в скрытый список ИЛИ Я пометить строку как удаленный с классом CSS и совок их в конце , перед подачей, например:

var deletedIds = []; 
$('myselector').each(function(){ deletedIds.push($(this).attr('data-rowId'));}); 
$('deletedIds').val(deletedIds.join(',')); 

Затем разделите строку на массив на сервере.

Если вы имеете дело с ними позиционно, и вы уверены, что последовательность на сервере не может меняться между запросами, я бы использовал тот же подход, но с использованием индекса массива, а не идентификатора.

+0

спасибо, но я не думаю, что это сработает. Для привязки модели MVC к удару имена полей формы должны соответствовать свойствам модели. Таким образом, «разделение строки обратно на массив» не является привязкой к модели, но в любом случае это не связующее устройство по умолчанию (вам понадобится пользовательский). – RPM1984

+0

В зависимости от ваших требований. Идея использования deletedIds заключается в привязке к отдельному полю в вашей модели viewmodel. Когда они нажимают кнопку «Удалить», вы удаляете строку на клиенте и обновляете поле deletedIds. Для добавлений вы создаете новую строку с идентификационным значением 0. Связыванию не важно, что такое массив, только если он похож на массив. Затем вы работаете на сервере, какие строки новые, глядя на их идентификаторы. Кроме того, я подозреваю, что MVC, вероятно, не заботится о том, какие числа у вас есть в массиве, если они соответствуют соглашениям об именах. Новые строки могут использовать любой идентификатор. –

2

Мне тоже пришлось иметь дело с такой же ситуацией. Самым простым решением я придумал, использует модель обертку, подобно:

public class QuestionListModel 
{ 
    public IList<QuestionModel> Questions { get; set; } 

    public IList<QuestionModel> Template 
    { 
     get 
     { 
      return new List<QuestionModel> 
         { 
          new QuestionModel {/* defaults for new question */} 
         }; 
     } 
    } 

    public QuestionListModel() 
    { 
     Questions = new List<QuestionModel>(); 
    } 
} 

Важная часть, является имея шаблон свойство , который также является IEnumerable<T> того же типа, что и фактической модели вы хотите. Таким образом, авто-нумерация будет выполнена для вас MVC. Таким образом, используя эту модель, вы получаете, свою коллекцию, с нумерацией «Questions_0__Title», и вы также получаете одну строку шаблона с названием «Template_0__Title».

Я держу свою строку шаблона скрытой от пользовательского интерфейса и использую ее при добавлении новой строки.

В бритве вы привязываете шаблон так же, как вы связываете регулярный вопрос, с той лишь разницей, что это было бы в скрытом <div>. Вам также потребуется связать Count вашего списка вопросов с скрытым полем. В моем случае у меня есть шаблон редактора для Вопроса, который отображает его внутри <div> с определенным селектором, для более легкого доступа позже. Так что вы в конечном итоге с что-то подобное:

<div class="templateContainer"> 
    <div class="question"> 
    [Template] 
    </div> 
</div> 
<div class="items"> 
    [for each of your items] 
    <div class="question"> 
    [Question] 
    </div> 
</div> 

При добавлении строки, уловка, с помощью JavaScript:

  1. Получить счет от скрытого поля, увеличиваем его.

    var counter = $("#QuestionsListCount"); 
        var count = parseInt(counter.val()); 
        count++; 
    
  2. Возьмите весь блок шаблона, клонировать его (с помощью JQuery-х .clone(true), например), назовите его как нечто уникальное (используя значение счетчика с шага 1, например), и добавить его в раздел, где ваши вопросы находятся.

    var template = $("#templateContainer"); 
        var newItem = template.clone(true); 
        var newId = "item_" + count; 
        var newQuestion = newItem.children().first(); 
        newQuestion.attr("id", newId); 
        newQuestion.appendTo('#items'); 
    
  3. Для каждого элемента, такие как входы в вашем новом приложенном блоке (вы можете найти его с новым идентификатором вы присвоенной ему), то заменить IdS => «Template_0» с «Questions__count от шага 2» , а имена => «Шаблон [0]» с «Вопросы [счет с шага 2]».

    $("#" + newId + " :input").each(function (index, input) { 
         input.id = input.id.replace("Template_0", "Questions_" + (count - 1)); 
         input.name = input.name.replace("Template[0]", "Questions[" + (count - 1) + "]"); 
        }); 
    
  4. Update скрытое поле для счетчика =>counter.val(count);

  5. ...
  6. прибыль!

Теперь, что касается удалений, как я это делаю, это мой ViewModel для него на самом деле имеет IsDeleted флаг, который я связываться скрытом поле в шаблоне Вопрос редактора, а также. Таким образом, удаления так же просто, как скрыть конкретный вопрос (вопрос селектор подходит), и вы установите для этого поля IsDeleted значение true. Когда вы возвращаете весь свой список обратно по умолчанию, вы должны отбросить все удаленные (или удалить фактические удаления, в зависимости от вашей исходной модели данных).

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

Это длинный пост, но реализация на самом деле не такая сложная (или длинная), и ее можно легко использовать в общем виде.

Cheers!

+0

Ницца. Тем не менее, это довольно сложно, потому что вам приходится гадать с атрибутами id/name, отслеживать счетчики и т. Д. Не знаю, почему кто-то не создал кого-то плагин jQuery/MVC, чтобы сделать все это для нас. – RPM1984

+0

Да, это правда. Что касается счетчиков, они вам действительно не нужны, поскольку вы можете определить его, посчитав все подэлементы селектором «вопрос». Но я согласен с тем, что вам все равно придется беспокоиться о идах и именах. Существует один путь, который заключается в создании пользовательского ModelBinder для него. В этом случае вы можете сгенерировать любой html, который вы предпочитаете (без субиндексов, например) и закодировать связующее, чтобы вернуть его обратно в модель. –

+0

Да, я могу пойти с поддельной моделью. если бы мне пришлось выполнять дополнительную работу, я бы предпочел сделать это на сервере, чем клиент. – RPM1984

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

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