Возникла необходимость использовать плагин bootstrap-modal.js для редактирования формы. Казалось бы тривиальная задача, но пришлось столкнуться с некоторыми сложностями. В данной статье поделюсь с вами своим решением, более изящные решения и здоровая критика приветствуются.
Имеется страница с формой для редактирования товара. Добавим на форму выпадающий список с перечнем производителей. Рядом разместим бутстраповскую иконку icon-plus-sing, которая и будет триггером для вызова модального окна.
<div id="edit_producer" class="modal fade hide in">
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Producers)
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.ProducerId, Model.Producers)
@Ajax.RawActionLink(
"<i class='icon-plus-sign icon-2x'></i>",
ActionConstants.Edit,
ProducerController.Name,
null,
new AjaxOptions
{
UpdateTargetId = "edit_producer",
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET",
OnSuccess = "ShowProducerEditModal"
},
null)
@Html.ValidationMessageFor(model => model.Producers)
</div>
</div>
Примечание: используются кастомные html-хелперы DropDownListFor и RawActionLink.
Идем дальше. Пишем js обработчик на событие OnSuccess.
function ShowProducerEditModal() {
$('#edit_producer').modal('show');
}
Далее нам нужен экшен в контроллере ProducerController для рендеринга содержимого модального окна.
[HttpGet]
public ActionResult Edit(long? id)
{
ProducerEditModel model = service.GetProducerEditModel(id);
return PartialView("ProducerEditPartial", model);
}
Частичное предстваление контента модального окна:
@using (Ajax.BeginForm(
ActionConstants.Edit,
ProducerController.Name,
new AjaxOptions
{
HttpMethod = "POST",
OnSuccess = "OnSuccess"
}))
{
<div class="modal-header">
<a class="close" data-dismiss="modal">×</a>
<h3>Редактирование производителя</h3>
</div>
<div class="modal-body">
@Html.HiddenFor(model => model.Id)
<div class="editor-label">
@Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="modal-footer">
<input type="submit" class="btn btn-success" value="Сохранить" />
<a href="#" class="btn" data-dismiss="modal">Close</a>
</div>
}
В результате получаем красивый попап с формой по клику на триггер.
Следом стоит задача валидации редактируемой формы и добавление нового элемента в выпадающий список. Для этого пишем обработчик события OnSuccess. Предусмотрим возможность добавления и редактирования элемента выпадающего списка. Если содержимое формы оказывается не валидным, то отрисовываем форму внутри модального окна ещё раз.
function OnSuccess(data) {
if (data.isValid) {
$('#edit_producer').modal('hide');
if (data.isNew) {
AppendToDropDownList(data.name, data.id, 'ProducerId');
} else {
EditDropDownListItem(data.name, data.id, 'ProducerId');
}
} else {
$('#edit_producer').html(data.partialView);
}
}
function AppendToDropDownList(text, value, ddlId) {
var newItem = $('<option/>', {
value: value,
text: text
});
$('#' + ddlId).append(newItem);
}
function EditDropDownListItem(text, value, ddlId) {
$('#' + ddlId + ' option[value="' + value + '"]').text(text).val(value);
}
В контроллер ProducerController пишем ещё один экшен.
Примечание: используется кастомный статический метод RenderRazorViewToString
[HttpPost]
public ActionResult Edit(ProducerEditModel model)
{
if (ModelState.IsValid)
{
bool isNew = model.Id == 0;
long id = service.Save(model);
return Json(new
{
isValid = true,
id = id,
name = model.Name,
isNew = isNew
});
}
return Json(new
{
partialView = RenderUtils.RenderRazorViewToString(this, "ProducerEditPartial", model),
isValid = false
});
}
В общем-то на этом все. Спасибо за внимание.
Полезные ссылки:
Русскоязычное руководство по bootstrap
Туториал по bootstrap-modal.js
Исходники bootstrap-modal.js
Автор: ne4ta