MVC和jQuery都很新,所以我不知道如何让它工作。我用一个ajax回发拼凑了一个(有点)工作模式对话框。一直在寻找两天,没有找到伟大的MVC + jQuery示例。数据按预期插入,这只是我很难用的UI。
我有两个观点:索引和创建。索引列出普通表中的所有记录,使用Razor循环结果。 Create是插入表单,我将其加载到模态对话框中:
@model IEnumerable<MyProject.Models.StockIndex>
@{
ViewBag.Title = "Admin: Stock Index Home";
Layout = "~/Views/Shared/_LayoutAdmin.cshtml";
}
<h2>View Stock Indices</h2>
<p>
<a href="#" id="createLink">Create New</a>
<div id="createStockIndexForm"></div>
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Description)
</th>
<th></th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
@Html.ActionLink("Details", "Details", new { id = item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
</table>
@section Scripts {
<script>
$('#createLink').on('click', function () {
$("#createStockIndexForm").dialog({
autoOpen: true,
position: { my: "center", at: "top+350", of: window },
width: 600,
resizable: false,
title: 'Create Stock Index',
modal: true,
open: function () {
$(this).load('@Url.Action("Create", "AdminStockIndex")');
}
});
return false;
});
</script>
}
控制器操作:
public ActionResult Create()
{
var model = new StockIndexEditViewModel()
{
StockIndices = GetIndices()
};
return View(model);
}
[HttpPost]
public ActionResult Create(StockIndexEditViewModel model)
{
if (ModelState.IsValid)
{
...
}
return PartialView(model);
}
加载到对话框中的“创建”表单(上图):
@model MyProject.Models.StockIndexEditViewModel
@{
ViewBag.Title = "CreatePartial";
Layout = "~/Views/Shared/_LayoutAdmin.cshtml";
}
<h2>CreatePartial</h2>
@using (Html.BeginForm("Create", "AdminStockIndex", FormMethod.Post, new { id = "createForm" }))
{
@Html.AntiForgeryToken()
<div id="result"></div>
<div class="form-horizontal">
<h4>StockIndexEditViewModel</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.SelectedParentId, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.SelectedParentId, Model.StockIndices, "- Select One -", new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Description, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Description, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Description, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" id="createButton" class="btn btn-default" />
</div>
</div>
</div>
}
@section Scripts {
<script>
$("#createForm").on("submit", function (event) {
event.preventDefault();
$.ajax({
url: this.action,
type: this.method,
async: true,
data: $(this).serialize(),
success: function (data) {
if (data) {
var createForm = $("#createStockIndexForm").dialog();
createForm.dialog("close");
}
else {
$("#result").append("Something went fail.");
}
}
});
});
</script>
}
模态对话框始终为空白,而不是关闭。在使用Firebug在Firefox中进行测试时,我偶尔会看到此错误,但不是每次都看到错误:
InvalidAccessError:不支持参数或操作 基础对象
在搜索时,我发现这是一个CORS问题,其中FF正在执行规则而其他浏览器可能不是。令人沮丧的是,错误并不总是发生 - 似乎是随机的。在Chrome中表现相同但不会在JS控制台中引发错误。
首先,我该如何解决这个问题?其次,有没有办法通过ajax刷新父页面上的表,没有插件?
更新
在Eckert的帮助下,我取得了一些进展。
我正在努力避免使用MVC Ajax助手并坚持使用“纯粹的”jQuery方法。我用一个div替换了Index上的记录列表,其中包含一个PartialView:
<div id="stockIndices">
@Html.Partial("_StockIndices", Model)
</div>
我通过使用jQuery对话框的close属性重新加载div来使基础表刷新工作:
$('#createLink').on('click', function () {
$("#createStockIndexForm").dialog({
autoOpen: true,
position: { my: "center", at: "top+400", of: window },
width: 600,
resizable: false,
title: 'Create Stock Index',
modal: true,
open: function () {
$(this).load('@Url.Action("Create", "AdminStockIndex")');
},
close: function () {
$("#stockIndices").load('@Url.Action("GetStockIndices", "AdminStockIndex")');
}
});
return false;
});
手动关闭模态对话框后,div会重新加载我想要的内容。大!现在如果我可以在表单发布时关闭对话框,我会被设置。这不起作用:
$("#createStockIndexForm").dialog("close");
Firebug报告错误:
错误:在初始化之前无法调用对话框上的方法; 试图调用方法'关闭'
答案 0 :(得分:1)
模态对话框始终为空白,而不是关闭。
它可能表现不正确,因为您根据对象的对话方法创建变量,而不是对象本身。试试这个:
if (data) {
$("#createStockIndexForm").dialog("close");
}
其次,有没有办法刷新父页面上的表格 ajax,没有插件?
确实如此,但可能需要您更改一些内容,包括关闭对话框的代码。以下是我将如何处理它:
1)您的记录表应该是主索引视图中的部分视图。这样做的原因是,当我们提交表单时,我们将使用ajax-option&#34; InsertionMode&#34;与target-id结合使用表单中更新的旧记录表替换旧记录表。
2)我们不是在提交方法中处理对话框关闭代码,而是使用ajax-option&#34; OnSuccess&#34;要做到这一点(以及&#34; OnFailure&#34;处理你的事情&#39;事情失败&#39;错误)。
所以,这是你的新索引视图:
@model IEnumerable<MyProject.Models.StockIndex>
@{
ViewBag.Title = "Admin: Stock Index Home";
Layout = "~/Views/Shared/_LayoutAdmin.cshtml";
}
<h2>View Stock Indices</h2>
<p>
<a href="#" id="createLink">Create New</a>
<div id="createStockIndexForm"></div>
</p>
<div id="recordsDiv">
@Html.Partial("RecordsPartial", model)
</div>
// all your script stuff can still go at the end
大多数索引视图都没有改变,但我们现在使用包含局部视图的视图除外。该部分视图将包括记录表,在此处编码:
创建名为&#34; RecordsPartial&#34;:
的新部分视图@model IEnumerable<MyProject.Models.StockIndex>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Description)
</th>
<th></th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
@Html.ActionLink("Details", "Details", new { id = item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
现在你的&#34;创建&#34;视图将更新为使用mvc-ajax助手而不是使用所有其他javascript代码:
@model MyProject.Models.StockIndexEditViewModel
@{
ViewBag.Title = "CreatePartial";
Layout = "~/Views/Shared/_LayoutAdmin.cshtml";
}
<h2>CreatePartial</h2>
@using (Ajax.BeginForm("CreateRecord", "AdminStockIndex", new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.Replace, UpdateTargetId = "recordsDiv", OnSuccess = "postSuccess", OnFailure = "postFailed" })
{
@Html.AntiForgeryToken()
<div id="result"></div>
<div class="form-horizontal">
<h4>StockIndexEditViewModel</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
/* form fields here */
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" id="createButton" class="btn btn-default" />
</div>
</div>
</div>
}
我们将您的表单更改为ajax-post,并且我们已添加了ajax-options来处理表单发布后发生的情况。在帖子之后返回的数据(我们更新的记录部分)将替换target-id&#34; recordsDiv&#34;的当前内容。 OnSuccess功能&#34; postSuccess&#34;将处理关闭对话框。 OnFailure功能&#34; postFailed&#34;会报告发生了一件坏事。最后要提到的是,我们改变了后期行动,从#34;创建&#34;到&#34; CreateRecord&#34;。在使用ajax-data返回时,我更喜欢使用唯一的动作名称。这只是一种更清洁的方法。
在我们定义新的&#34; CreateRecord&#34;之前在行动之后,我们需要实施我们的成功和失败功能。只需在主&#34;索引&#34;中的脚本部分块的底部创建它们。视图:
@section Scripts {
<script>
// ... other stuff that was already here ...
function postSuccess() {
$("#createStockIndexForm").dialog("close");
}
function postFailed() {
alert("Failed to post"); // you can define your own error
}
</script>
}
最后,我们创建&#34; CreateRecord&#34; post-action,它将处理我们的表单并返回更新的&#34;记录部分&#34;视图:
[HttpPost]
public ActionResult CreateRecord(StockIndexEditViewModel model)
{
if (ModelState.IsValid)
{
... create record here ...
}
var records = db.Indexes.ToList(); // or whatever your table name is
return PartialView("RecordsPartial", records);
}
这是重复你现有的一些&#34;创建&#34;行动。我们只是处理我们的帖子数据,然后我们得到一个新的更新记录列表,最后我们将记录列表返回给我们的&#34; RecordsPartial&#34;视图,将被插入我们的&#34; recordsDiv&#34;正如我们在ajax-options中指定的那样。
非常简洁的解决方案。如果您有任何疑问,请随时提出。
答案 1 :(得分:1)
在主索引视图中,不是要求将您的“创建”视图插入到视图中,而是让它最初出现在视图加载中,并将其隐藏在div中:
<div id="createStockIndexForm">
@Html.Action("Create", "AdminStockIndex")
</div>
在您的索引脚本部分,我们正在创建您的点击事件外的对话框。我们也将“autoOpen”值变为false,因此div隐藏在视图加载状态。
索引脚本部分:
@section Scripts {
<script>
$("#createStockIndexForm").dialog({
autoOpen: false,
position: { my: "center", at: "top+350", of: window },
width: 600,
resizable: false,
title: 'Create Stock Index',
modal: true
});
$('#createLink').on('click', function () {
$("#createStockIndexForm").show();
});
</script>
}
此外,当您使用PreventDefault()命令时,它似乎干扰了您的模态关闭命令(在我自己的一些测试之后)。我建议您更改表单的“创建”按钮以键入=“按钮”而不是“提交”,然后使用按钮的ID来处理您的ajax-post方法。
<input type="button" id="createButton" value="Create" class="btn btn-default" />
将其添加到底部的主索引脚本部分:
$("#createButton").on("click", function () {
$.ajax({
url: this.action,
type: this.method,
async: true,
data: $(this).serialize(),
success: function (data) {
if (data) {
$("#createStockIndexForm").dialog("close");
}
else {
$("#result").append("Something went fail.");
}
}
});
});
确保将“关闭”命令指向对话框对象本身。
这是我创建的小提琴,它向您展示了它应该是什么的要点: http://jsfiddle.net/ch5aLezg/
因此,回顾一下脚本的内容,你的“创建”部分应该没有任何脚本。所有脚本都进入主索引视图,正如我在这个答案中详述的那样。
答案 2 :(得分:1)
我找到了一种方法来获得我想要的一切,同时保留了纯粹的&#34; Eckert建议使用jQuery Ajax方法,而不是求助于MVC Ajax助手。然而,他的建议引导我找到解决方案。非常感谢!
我在控制器中创建了一个PartialView:
public ActionResult GetStockIndices()
{
_service = new StockIndexService();
var data = _service.GetAll();
return PartialView("_StockIndices", data);
}
......及其观点:
@model IEnumerable<MyApp.Models.StockIndex>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Description)
</th>
<th></th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
@Html.ActionLink("Details", "Details", new { id = item.Id }) |
@Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
</table>
然后我更改了模态对话框脚本以在关闭时加载局部视图。对于子孙后代,这里是整个索引视图:
@model IEnumerable<MyApp.Models.StockIndex>
@{
ViewBag.Title = "Admin: Stock Index Home";
Layout = "~/Views/Shared/_LayoutAdmin.cshtml";
}
<h2>View Stock Indices</h2>
<p>
<a href="#" id="createLink">Create New</a>
<div id="createStockIndexForm"></div>
</p>
<div id="stockIndices">
@Html.Partial("_StockIndices", Model)
</div>
@section Scripts {
<script>
var _dialog;
$('#createLink').on('click', function () {
_dialog = $("#createStockIndexForm").dialog({
autoOpen: true,
position: { my: "center", at: "top+400", of: window },
width: 600,
resizable: false,
title: 'Create Stock Index',
modal: true,
open: function () {
$(this).load('@Url.Action("Create", "AdminStockIndex")');
},
close: function () {
$("#stockIndices").load('@Url.Action("GetStockIndices", "AdminStockIndex")');
}
});
return false;
});
</script>
}
注意全球&#34; _dialog&#34;变量。这使我可以从“创建”表单访问该对话框,因此可以将其关闭:
<script>
$("#createForm").on("submit", function (event) {
event.preventDefault();
$.ajax({
url: this.action,
type: this.method,
async: true,
data: $(this).serialize(),
success: function (data) {
if (data) {
if (_dialog) {
_dialog.dialog("close");
}
}
else {
$("#result").append("Error! Record could not be added.");
}
},
error: function (error) {
console.error(error);
}
});
});
</script>