Подтвердить что ты не робот

Общепринятый подход в MVC для формы в диалоговом окне jQuery

Кажется, есть несколько способов интегрировать диалоги jQuery с ASP.NET MVC. Имеет ли конкретный подход как общепринятый способ наилучшей практики?

В качестве примера: у меня есть страница списка, где нажатие "edit" для любого из перечисленных элементов открывает форму в диалоговом окне jQuery, заполненном деталями. Пользователь редактирует детали и нажимает "Сохранить". Если сохранение успешно выполняется на стороне сервера, диалог закрывается, и список перестраивается со свежими данными. Если сбой сбоя на стороне сервера, диалог остается открытым и отображает сообщение об ошибке пользователю.

  • Подход No-JSON: каждая ссылка "edit" является HREF для действия контроллера "edit". Это действие контроллера создает представление, которое идентично представлению "список", плюс оно включает частичное действие для создания формы редактирования, заполнения и определения javascript, чтобы открыть его как диалог jquery. "Сохранить" - это форма-сообщение; если он преуспевает, он возвращает действие перенаправления на страницу списка. Если это не удается, он перестраивает всю страницу (включая форму, которая появляется в диалоговом окне), также отображая сообщения об ошибках.
  • подход All-JSON: страница списка отображает пустую форму редактирования (скрытую), готовую к открытию в диалоговом окне. Ссылка "edit" вызывает локальный javascript, который выполняет запрос ajax для получения полного объекта (я определяю контроллер, который возвращает полный объект как JsonResult). При успехе он заполняет форму редактирования данными объекта и открывает диалог. Ссылка "save" вызывает локальный javascript, который связывает данные формы с объектом json и вызывает операцию post с этим json-объектом в качестве полезной нагрузки (я определяю контроллер, который ожидает этот объект, пытается сохранить и возвращает JsonResult, указывающий на успех/отказ + ErrorMessages). Обратный вызов успеха из запроса ajax оценивает возвращаемый объект и отображает сообщения об ошибках в диалоговом окне все еще открытого jquery или закрывает диалоговое окно и перезагружает страницу "Список", чтобы получить свежие данные в списке.
  • [Изменить] Ajax-HTML-подход: просто увидел эту дискуссию, в которой описывается другой подход. "Редактировать" вызывает локальный javascript, который выполняет пост ajax, чтобы получить ПОЛНЫЙ HTML-диалог (я бы написал контроллер, который возвращает частичное представление: полностью заполненная форма). Он отображает возвращаемый HTML в диалоговом окне jquery, а также "повторно прокладывает" представление формы для создания ajax-сообщения содержимого формы (я бы написал контроллер httpPost, такой же, как в предыдущем примере 2). Обратный вызов успеха оценивает ответ и заполняет сообщения об ошибках или закрывает диалог.
  • Какой-то другой классный подход, о котором я не думал?

Вариант 1, похоже, больше соответствует "чистым" ASP.NET MVC. Тем не менее, он, как представляется, содержит большие HTTP-нагрузки (поскольку мы отправляем всю страницу обратно в браузер по каждому запросу) и более медленную производительность на стороне сервера (поскольку мы перестраиваем список по каждому запросу).

Вариант 2, похоже, более совместим с более современными веб-приложениями на основе Ajax (меньшими полезными нагрузками HTTP, более подробными операциями). Тем не менее, похоже, что многие контроллеры будут контроллерами JSON, и я буду писать много клиентского кода для маршалирования данных из объектов JSON в/из полей формы, отображения сообщений об ошибках и т.д. Это также похоже на я 'd будет отсутствовать на множестве интересных функций MVC, таких как EditorFor() и ValidationMessageFor(). Он просто "чувствует", как будто я работаю над системой MVC, а не с ней.

[Изменить: добавлена ​​опция 3] Вариант 3 кажется немного гибридным между 1 и 2. Я использую "чистый" подход MVC для создания и заполнения формы и возврата полностью сформированный тег HTML FORM. Возврат HTML к запросу ajax кажется странным, поскольку он настолько подробный, но я могу его преодолеть. Операция post - приятный, компактный JSON, который "чувствует" себя лучше над ajax. Однако, к сожалению, объект полезной нагрузки является FormCollection, а не реальным объектом viewmodel. Похоже, я могу использовать некоторые из удобств MVC (EditorFor()), но не другие (ValidationMessageFor()).

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

Я довольно опытна в ASP.NET/C#, но я довольно новичок в MVC. Заранее благодарим за помощь!

[изменить]- выдающиеся ответы - я бы хотел наградить несколько ответов/награды, так как я нашел несколько ответов чрезвычайно полезными. Но, поскольку я не могу, я отмечаю ответ, который считается самым высоким, как ответ. Еще раз спасибо всем респондентам!

4b9b3361

Ответ 1

У моей команды и у меня большой опыт написания приложений MVC с поддержкой AJAX, и мы использовали все 3 подхода.

Однако мой любимый, безусловно, подход AJAX-HTML. Используйте PartialView, чтобы отобразить содержимое диалогового окна, которое может включать сообщения о проверке на стороне сервера и любую другую логику.

Самое большое преимущество этого подхода - разделение проблем. Ваши представления всегда отвечают за визуализацию вашего HTML, а ваш JavaScript не должен содержать текст, разметку или "шаблоны", необходимо было сделать JSON.

Еще одно большое преимущество в том, что все возможности MVC доступны для рендеринга HTML: строго типизированные представления, HtmlHelper, DisplayFor и EditorFor шаблоны, DataAnnotations и т.д. Это упрощает согласованно и хорошо поддается рефакторингу.

Просто помните, что нет требования придерживаться единого подхода. Если для вызова AJAX требуется только что-то простое, например обновление статуса, например "Успех", достаточно просто использовать string или JSON для передачи этих сообщений. Используйте PartialViews, когда требуется HTML, и используйте более простые методы, когда требуется общение.

Ответ 2

Ваш второй метод, подход All-JSON, по-видимому, все более распространен с библиотеками на стороне клиента MVC и MVVM, такими как Knockout

В этом вы могли бы фактически иметь все данные в JSON (включая список) и редактировать элементы списка (похожие на их демонстрацию редактора элементов списка, только с отображением диалога isntead inline и привязки данных к readonly охватывает в ваших ячейках), а затем сериализуйте всю совокупность набора обратно на сервер при сохранении. Или вы можете сделать это с кусочком пищи после каждого всплывающего редактирования.

JSFiddle: http://jsfiddle.net/paultyng/weLtH/17/

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

Ответ 3

Я думаю, что лучший способ - сделать список обычным. Подключите ссылки редактирования, чтобы перейти на отдельную страницу (следуйте за мной здесь), как обычно.

Когда JS обрабатывает щелчок по ссылке, и сделайте доступ к ней href. В действии редактирования выполните проверку для Request.IsAjaxRequest(), и если это так, верните частичный вид, если это не так, верните полное представление. Или визуализируйте нормальный вид редактирования без главной страницы (перейдите в нуль к параметру главной страницы в вызове View() или возвратите вызов Partial()). Возьмите содержимое результата и поместите его в диалог.

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

Преимущество такого подхода очень ненавязчиво и до сих пор позволяет функционировать для тех, у кого нет JS.

Ответ 4

Хорошо, поэтому ваши варианты в значительной степени сжигают концепцию прогрессивного улучшения здесь. 2 и 3 не будут работать, если ваш клиент не поддерживает java script. Очевидно, что это нормально, если вам все равно, но я думаю, что я попытаюсь спроектировать вещи так, чтобы они деградировали изящно, и вы просите о лучшей практике здесь.

Итак, способ, которым я его построил, начинается с вашего варианта 1. У вас есть кнопки редактирования, которые запускают другое действие, которое загружает страницу редактирования, и эта страница разработана со всеми валидаторами и т.д. в соответствии с обычным mvc. Что ваша базовая функциональность работает без js.

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

Ну, первым шагом будет создание обработчика, чтобы открыть диалог, прикрепленный к редактируемым ссылкам при щелчке (убедитесь, что e.PreventDefault). Теперь, чтобы сэкономить слишком много усилий по кодированию, я хотел бы повторно использовать страницу редактирования. Это потребует немного рефакторинга, хотя вы не хотите включать макет для запросов ajax. Вы можете сделать это несколькими способами, но я думаю, что самое чистое - иметь область редактирования представления редактирования как частичное представление, которое используется основным видом редактирования для рендеринга его модели.

Затем в вашем действии редактирования вы можете проверить, есть ли у вас запрос ajax, если да, тогда возвратите PartialView (mypartialeditview) или View (editview), если нет.

С точки зрения отправки результатов на сервер, если вы хотите, чтобы простая жизнь просто рассматривала его как форму. Здесь вы можете использовать softosoft unabstrive ajax, и это будет очень просто. Вы используете Ajax.BeginForm в частичном представлении. n.b.Это будет деградировать до нормальной формы, если ajax недоступен. Попросите AjaxOptions для этого набора beginform обновить div в диалоге, поэтому, если он отвечает своим html, вам больше не нужно ничего делать, это подразумевает ошибку проверки.

[немного в сторону, как вы сказали выше об этом: с точки зрения обработчика HttpPost, связующее устройство модели по умолчанию является удивительно умным, оно может привязывать поля формы к свойствам в параметре объекта сложного класса. Это также работает с json, поэтому вам не нужно много методов действий для поддержки различных сценариев.]

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

Если вам не нравится делать полную перезагрузку главной страницы, тогда она становится более сложной, так как с помощью подхода выше вы возвращаете html. Вам придется либо выполнить jquery, чтобы найти скрытое поле или класс, чтобы указать успех/неудачу, либо перейти на чистый подход json, который возвращает jsonresult. Тем не менее, это становится все более тяжелым на уровне обслуживания/кодирования. Я бы, вероятно, выполнил проверку jquery и подключил его к обработчику завершения ajax.Beginform.

Если вы действительно хотите обмануть этот материал, я обнаружил, что книга Стив Сандерсон Pro Asp.net MVC неоценима. Я сначала прочитал для MVC2, но только в процессе чтения обновления MVC3. У меня смешанные чувства по поводу обновления, так как его упростили в нескольких местах - теперь это легче, но я чувствую, что некоторые вещи отсутствуют, также он был брошен как некоторые ошибки и т.д., Когда он приближается к концу. Я думаю, возможно, они запаниковали теперь, когда о MVC4 говорят, а книги не было! Тем не менее хорошая книга, хотя и прекрасно охватывает все это.

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

Ответ 5

Использование jQuery.tmpl() плагина 1

Я использую аналогичный сценарий, но делаю это по-другому.

У меня есть главный список, где каждый элемент обернут в контейнер (будь то таблица TR или DIV). Некоторая общая информация об элементе отображается в главном списке, когда слишком много данных содержится в простом списке. Следовательно, главный список, а не детали (конечно).

Каждый контейнер элемента обычно записывается следующим образом:

<div class="item" data='<%= item.ToJson() %>'> <!-- single quotes! -->
    item visible list data
</div>

Основная часть здесь - мой пользовательский метод расширения ToJson(), который сериализует данные моего элемента, которые могут быть легко использованы на клиенте.

Затем у меня есть шаблон jQuery в конце списка, содержащегося внутри тега script. Этот шаблон является фактическим содержимым диалогового окна редактирования со всеми переменными элементов, установленными по мере необходимости.

Всякий раз, когда пользователь нажимает на редактирование элемента, я просто разбираю элемент JSON с помощью:

// in edit link click handler
var itemData = $.parseJSON($(this).closest("[data]").attr("data"));
// display dialog
displayDialog($("#editDialog").tmpl(itemData));

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

Таким образом, мой HTML-код минимален (имеет только один шаблон), а JSON также содержит только те свойства, которые действительно необходимы.

Что делать, если ваш класс модели имеет ссылки на другие сущности?

Это довольно распространено, что сущности связаны между собой. Предположим, что у вас есть объекты Post и Comment:

public class Post
{
    public int Id { get; set; }

    public string Body { get; set; }

    public IList<Comment> Comments { get; set; }
}

Конечно, вы не интересуетесь связанными объектами при преобразовании своих элементов в JSON на сервере. Вот почему вы можете поместить атрибут в связанные свойства, чтобы они не включались в JSON:

public class Post
{
    public int Id { get; set; }

    public string Body { get; set; }

    [ScriptIgnore]   
    public IList<Comment> Comments { get; set; }
}

Это заставит JSON-сериализатор игнорировать связанное свойство, которое мы не будем редактировать в редакторе наших данных.

ToJson() код расширения

Последнее, что нужно сделать, это код метода расширения, вот он:

public static class ObjectExtensions
{
    /// <summary>
    /// Serializes this object instance to JSON string.
    /// </summary>
    /// <param name="instance">Object instance being extended.</param>
    /// <returns>Returns a JSON string that represents current object instance.</returns>
    public static string ToJson(this object instance)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        // register custom class converters
        serializer.RegisterConverters(...);
        return serializer.Serialize(instance);
    }

    /// <summary>
    /// Serializes this object instance to JSON string.
    /// </summary>
    /// <param name="instance">Object instance being extended.</param>
    /// <param name="recursionDepth">Serialization recursion limit depth.</param>
    /// <returns>Returns a JSON string that represents current object instance.</returns>
    public static string ToJson(this object instance, int recursionDepth)
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        // register custom class converters
        serializer.RegisterConverters(...);
        serializer.RecursionLimit = recursionDepth;
        return serializer.Serialize(instance);
    }
}

Что делать, если объекты слишком сложны?

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

  • ваши объекты сложны или имеют длинные данные (длинные в терминах сериализованной строки)
  • определение объектов JSON для всех элементов будет слишком трудоемким.
  • неизвестный объект JSON во время отображения главного списка.

то вы всегда можете отправить удаленный вызов Ajax на сервер для одного объекта и вернуть либо

  • Объект JSON для использования с шаблоном диалога
  • возврат частичного представления с помощью редактора

Второй подход лучше, поскольку преобразование экземпляра объекта в HTML или JSON практически аналогично. но во втором случае нет необходимости в обработке шаблонов на стороне клиента.

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

1: ссылка API шаблона jQuery