MVC 4 使用 Bootstrap 编辑模态表单
Posted
技术标签:
【中文标题】MVC 4 使用 Bootstrap 编辑模态表单【英文标题】:MVC 4 Edit modal form using Bootstrap 【发布时间】:2013-04-07 07:54:38 【问题描述】:我正在使用 MVC 4 和 Entity Framework 来开发 Intranet Web 应用程序。我有一个可以通过编辑操作修改的人员列表。我想通过使用模态表单使我的应用程序更加动态。所以我尝试将我的编辑视图放入我的 Bootstrap 模式中,我有两个问题:
我应该使用简单视图还是局部视图? 我如何执行验证(实际上它可以工作,但它会将我重定向到我的原始视图,因此不在模态表单中)我认为我必须使用 AJAX 和/或 jQuery,但我对这些技术不熟悉。任何帮助将不胜感激。
编辑:我的索引视图:
@model IEnumerable<BuSIMaterial.Models.Person>
@
ViewBag.Title = "Index";
<h2>Index</h2>
<br />
<div class="group">
<input type="button" value="New person" class="btn" onclick="location.href='@Url.Action("Create")';return false;"/>
<input type="button" value="Download report" class="btn" onclick="location.href='@Url.Action("PersonReport")';return false;"/>
</div>
@using (html.BeginForm("SelectedPersonDetails", "Person"))
<form class="form-search">
<input type="text" id="tbPerson" name="tbPerson" placeholder="Find an employee..." class="input-medium search-query">
<button type="submit" class="btn">Search</button>
</form>
<table class="table">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Start Date</th>
<th>End Date</th>
<th>Details</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach (BuSIMaterial.Models.Person item in ViewBag.PageOfPersons)
<tr>
<td>@item.FirstName</td>
<td>@item.LastName</td>
<td>@item.StartDate.ToShortDateString()</td>
<td>
@if (item.EndDate.HasValue)
@item.EndDate.Value.ToShortDateString()
</td>
<td>
<a class="details_link" data-target-id="@item.Id_Person">Details</a>
</td>
<td>
<div>
<button class="btn btn-primary edit-person" data-id="@item.Id_Person">Edit</button>
</div>
</td>
</tr>
<tr>
<td colspan="6">
<table>
<tr>
<th>National Number</th>
<td>@item.NumNat</td>
</tr>
<tr>
<th>Vehicle Category</th>
<td>@item.ProductPackageCategory.Name</td>
</tr>
<tr>
<th>Upgrade</th><td>@item.Upgrade</td>
</tr>
<tr>
<th>House to work</th>
<td>@item.HouseToWorkKilometers.ToString("G29")</td>
</tr>
</table>
<div id="details_@item.Id_Person"></div>
</td>
</tr>
</tbody>
</table>
<div class="modal hide fade in" id="edit-member">
<div id="edit-person-container"></div>
</div>
@section Scripts
@Scripts.Render("~/bundles/jqueryui")
@Styles.Render("~/Content/themes/base/css")
<script type="text/javascript" language="javascript">
$(document).ready(function ()
$('#tbPerson').autocomplete(
source: '@Url.Action("AutoComplete")'
);
$(".details_link").click(function ()
var id = $(this).data("target-id");
var url = '/ProductAllocation/ListByOwner/' + id;
$("#details_"+ id).load(url);
);
$('.edit-person').click(function ()
var url = "/Person/EditPerson";
var id = $(this).attr('data-id');
$.get(url + '/' + id, function (data)
$('#edit-person-container').html(data);
$('.edit-person').modal('show');
);
);
);
</script>
我的部分观点:
@model BuSIMaterial.Models.Person
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Edit</h3>
</div>
<div>
@using (Ajax.BeginForm("EditPerson", "Person", FormMethod.Post,
new AjaxOptions
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "list-of-people"
))
@Html.ValidationSummary()
@Html.AntiForgeryToken()
<div class="modal-body">
<div class="editor-field">
@Html.TextBoxFor(model => model.FirstName, new maxlength = 50 )
@Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.LastName, new maxlength = 50 )
@Html.ValidationMessageFor(model => model.LastName)
</div>
</div>
<div class="modal-footer">
<button class="btn btn-inverse" type="submit">Save</button>
</div>
【问题讨论】:
嗨,traffy,您是否完成了如何使用引导程序编辑模态表单?我有同样的问题,你能更新或发布完整的代码吗? 【参考方案1】:您应该使用局部视图。我使用以下方法:
使用视图模型,这样您就不会将域模型传递给您的视图:
public class EditPersonViewModel
public int Id get; set; // this is only used to retrieve record from Db
public string Name get; set;
public string Age get; set;
在你的PersonController:
[HttpGet] // this action result returns the partial containing the modal
public ActionResult EditPerson(int id)
var viewModel = new EditPersonViewModel();
viewModel.Id = id;
return PartialView("_EditPersonPartial", viewModel);
[HttpPost] // this action takes the viewModel from the modal
public ActionResult EditPerson(EditPersonViewModel viewModel)
if (ModelState.IsValid)
var toUpdate = personRepo.Find(viewModel.Id);
toUpdate.Name = viewModel.Name;
toUpdate.Age = viewModel.Age;
personRepo.InsertOrUpdate(toUpdate);
personRepo.Save();
return View("Index");
接下来创建一个名为_EditPersonPartial
的局部视图。这包含模态页眉、正文和页脚。它还包含 Ajax 表单。它是强类型的并接受我们的视图模型。
@model Namespace.ViewModels.EditPersonViewModel
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Edit group member</h3>
</div>
<div>
@using (Ajax.BeginForm("EditPerson", "Person", FormMethod.Post,
new AjaxOptions
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "list-of-people"
))
@Html.ValidationSummary()
@Html.AntiForgeryToken()
<div class="modal-body">
@Html.Bootstrap().ControlGroup().TextBoxFor(x => x.Name)
@Html.Bootstrap().ControlGroup().TextBoxFor(x => x.Age)
</div>
<div class="modal-footer">
<button class="btn btn-inverse" type="submit">Save</button>
</div>
现在在你的应用程序的某个地方,说另一个部分 _peoplePartial.cshtml 等:
<div>
@foreach(var person in Model.People)
<button class="btn btn-primary edit-person" data-id="@person.PersonId">Edit</button>
</div>
// this is the modal definition
<div class="modal hide fade in" id="edit-person">
<div id="edit-person-container"></div>
</div>
<script type="text/javascript">
$(document).ready(function ()
$('.edit-person').click(function ()
var url = "/Person/EditPerson"; // the url to the controller
var id = $(this).attr('data-id'); // the id that's given to each button in the list
$.get(url + '/' + id, function (data)
$('#edit-person-container').html(data);
$('#edit-person').modal('show');
);
);
);
</script>
【讨论】:
有很多原因,请查看此答案以获取解释***.com/questions/4878937/… 如果您在我的回答方面需要任何帮助,请询问。 非常感谢!事实上,我有一个小问题:在您的 Ajax.Begin 表单中,“人员列表”代表什么? 您的应用中可能有一个 DIV,其中包含 id="list-of-people" 的人员列表。 UpdateTargetId 是您要使用 Ajax 表单(即人)中的新数据更新的 DIV/元素。只需专注于首先打开模式窗口,然后使用表单。 您的 POST 方法可能有问题。在其上放置断点并调试并查看发生了什么。实际上,在我对 POST 方法的回答中,为了简单起见,我只是说 return View()。您可能想尝试 return PartialView("SomePartial"); 您的视图中只有两个属性,其中之一不能满足验证。确保您输入的内容满足您在 Person 模型中的属性上放置的任何验证属性。将您的人物模型添加到问题中,或者专门针对该问题打开一个新问题。【参考方案2】:我更喜欢避免使用Ajax.BeginForm
助手,而是使用 JQuery 进行 Ajax 调用。以我的经验,维护这样编写的代码更容易。下面是详细信息:
模型
public class ManagePeopleModel
public List<PersonModel> People get; set;
... any other properties
public class PersonModel
public int Id get; set;
public string Name get; set;
public int Age get; set;
... any other properties
父视图
这个视图包含以下内容:
要迭代的人员记录 一个空的 div,当需要编辑 Person 时,将填充模态框 一些 JavaScript 处理所有 ajax 调用@model ManagePeopleModel
<h1>Manage People</h1>
@using(var table = Html.Bootstrap().Begin(new Table()))
foreach(var person in Model.People)
<tr>
<td>@person.Id</td>
<td>@Person.Name</td>
<td>@person.Age</td>
<td>@html.Bootstrap().Button().Text("Edit Person").Data(new @id = person.Id ).Class("btn-trigger-modal")</td>
</tr>
@using (var m = Html.Bootstrap().Begin(new Modal().Id("modal-person")))
@section Scripts
<script type="text/javascript">
// Handle "Edit Person" button click.
// This will make an ajax call, get information for person,
// put it all in the modal and display it
$(document).on('click', '.btn-trigger-modal', function()
var personId = $(this).data('id');
$.ajax(
url: '/[WhateverControllerName]/GetPersonInfo',
type: 'GET',
data: id: personId ,
success: function(data)
var m = $('#modal-person');
m.find('.modal-content').html(data);
m.modal('show');
);
);
// Handle submitting of new information for Person.
// This will attempt to save new info
// If save was successful, it will close the Modal and reload page to see updated info
// Otherwise it will only reload contents of the Modal
$(document).on('click', '#btn-person-submit', function()
var self = $(this);
$.ajax(
url: '/[WhateverControllerName]/UpdatePersonInfo',
type: 'POST',
data: self.closest('form').serialize(),
success: function(data)
if(data.success == true)
$('#modal-person').modal('hide');
location.reload(false)
else
$('#modal-person').html(data);
);
);
</script>
局部视图
此视图包含一个将填充有关人员信息的模式。
@model PersonModel
@
// get modal helper
var modal = Html.Bootstrap().Misc().GetBuilderFor(new Modal());
@modal.Header("Edit Person")
@using (var f = Html.Bootstrap.Begin(new Form()))
using (modal.BeginBody())
@Html.HiddenFor(x => x.Id)
@f.ControlGroup().TextBoxFor(x => x.Name)
@f.ControlGroup().TextBoxFor(x => x.Age)
using (modal.BeginFooter())
// if needed, add here @Html.Bootstrap().ValidationSummary()
@:@Html.Bootstrap().Button().Text("Save").Id("btn-person-submit")
@Html.Bootstrap().Button().Text("Close").Data(new dismiss = "modal" )
控制器操作
public ActionResult GetPersonInfo(int id)
var model = db.GetPerson(id); // get your person however you need
return PartialView("[Partial View Name]", model)
public ActionResult UpdatePersonInfo(PersonModel model)
if(ModelState.IsValid)
db.UpdatePerson(model); // update person however you need
return Json(new success = true );
// else
return PartialView("[Partial View Name]", model);
【讨论】:
两个问题: 1.如何为这个例子添加验证摘要? 2. 如果我复制你的代码,f.ControlGroup 是可用的。 我更新了代码。 (1) 您可以将ValidationSummary
放在模态代码中的任何位置。 (2) .Bootstrap()
扩展是通过使用TwitterBootstrapMVC 提供的
这一行给了我很多错误:@using (var m = Html.Bootstrap().Begin(new Modal().Id("modal-person"))) :::: : 没有名为 Bootstrap 的 Html 助手。找不到类型或命名空间“Modal”。
@JustJohn,阅读上面提到TwitterBootstrapMVC的评论
@Dmitry 谢谢!我的眼睛被这种模态的东西越过了。【参考方案3】:
在回复 Dimitrys 的回答但使用 Ajax.BeginForm
时,以下内容至少适用于 MVC >5(4 未测试)。
按照其他答案所示编写模型,
在“父视图”中,您可能会使用表格来显示数据。
模型应该是一个可枚举的。我假设,该模型有一个id
-property。然而,在模板下方,模态和相应 javascript 的占位符
<table>
@foreach (var item in Model)
<tr> <td id="editor-success-@item.Id">
@Html.Partial("dataRowView", item)
</td> </tr>
</table>
<div class="modal fade" id="editor-container" tabindex="-1"
role="dialog" aria-labelledby="editor-title">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content" id="editor-content-container"></div>
</div>
</div>
<script type="text/javascript">
$(function ()
$('.editor-container').click(function ()
var url = "/area/controller/MyEditAction";
var id = $(this).attr('data-id');
$.get(url + '/' + id, function (data)
$('#editor-content-container').html(data);
$('#editor-container').modal('show');
);
);
);
function success(data,status,xhr)
$('#editor-container').modal('hide');
$('#editor-content-container').html("");
function failure(xhr,status,error)
$('#editor-content-container').html(xhr.responseText);
$('#editor-container').modal('show');
</script>
注意数据表行中的“editor-success-id”。
dataRowView
是包含模型项目展示的部分内容。
@model ModelView
@
var item = Model;
<div class="row">
// some data
<button type="button" class="btn btn-danger editor-container" data-id="@item.Id">Edit</button>
</div>
编写通过单击行按钮调用的局部视图(通过 JS $('.editor-container').click(function () ...
)。
@model Model
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="editor-title">Title</h4>
</div>
@using (Ajax.BeginForm("MyEditAction", "Controller", FormMethod.Post,
new AjaxOptions
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "editor-success-" + @Model.Id,
OnSuccess = "success",
OnFailure = "failure",
))
@Html.ValidationSummary()
@Html.AntiForgeryToken()
@Html.HiddenFor(model => model.Id)
<div class="modal-body">
<div class="form-horizontal">
// Models input fields
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
这就是神奇的地方:在AjaxOptions
中,UpdateTargetId 将替换编辑后的数据行,onfailure 和 onsuccess 将控制模态。
这个就是modal只有在编辑成功并且没有错误的时候才会关闭,否则在ajax-posting之后会显示modal来显示错误信息,例如验证摘要。
但是如何让ajaxform知道是否有错误呢?这是控制器部分,只需在步骤 5 中更改 response.statuscode 如下:
部分编辑模态对应的控制器动作方法
[HttpGet]
public async Task<ActionResult> EditPartData(Guid? id)
// Find the data row and return the edit form
Model input = await db.Models.FindAsync(id);
return PartialView("EditModel", input);
[HttpPost, ValidateAntiForgeryToken]
public async Task<ActionResult> MyEditAction([Bind(Include =
"Id,Fields,...")] ModelView input)
if (TryValidateModel(input))
// save changes, return new data row
// status code is something in 200-range
db.Entry(input).State = EntityState.Modified;
await db.SaveChangesAsync();
return PartialView("dataRowView", (ModelView)input);
// set the "error status code" that will redisplay the modal
Response.StatusCode = 400;
// and return the edit form, that will be displayed as a
// modal again - including the modelstate errors!
return PartialView("EditModel", (Model)input);
这样,如果在模态窗口中编辑模型数据时发生错误,错误将在MVC的validationsummary方法的模态中显示;但如果更改提交成功,将显示修改后的数据表,模态窗口消失。
注意:你让 ajaxoptions 工作,你需要告诉你的包配置绑定jquery.unobtrusive-ajax.js
(可能由 NuGet 安装):
bundles.Add(new ScriptBundle("~/bundles/jqueryajax").Include(
"~/Scripts/jquery.unobtrusive-ajax.js"));
【讨论】:
感谢有用的提示。我的一条评论是,服务器可能在不同情况下返回不同于 200 的状态,例如由于内部服务器错误。这将触发 OnFailure 函数并将模式的内容替换为从服务器返回的任何内容。为了解决这个问题,我设置了一个像Response.Headers.Add("X-AjaxInvalidModel", "");
这样的自定义标头,然后在替换模态内容之前检查它在客户端上的存在:'isInvalidModel': function (xhr) return (typeof xhr.getResponseHeader('X-AjaxInvalidModel') === 'string');
。【参考方案4】:
在$('.editor-container').click(function ())
中,var url = "/area/controller/MyEditAction";
不应该是var url = "/area/controller/EditPartData";
吗?
【讨论】:
这是个问题吗?它看起来像一个。如果是,请删除它并使用“”按钮正确询问。如果令我惊讶的是,您认为这是一个答案,那么请edit 使答案更明显,并减少您在只允许答案的地方提出自己的问题的印象。以上是关于MVC 4 使用 Bootstrap 编辑模态表单的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Bootstrap 4 模态表单中重置单选按钮和复选框? [复制]