与MVC 3 - Ajax.BeginForm does a full post back类似,但我已经确认我的页面中存在对jquery.unobtrusive-ajax.min.js的引用。此外,它在IE 9中运行良好,但在Firefox和Chrome中,我只将部分视图作为完整的网页而不是用部分视图的内容替换div。
我还是MVC3的新手,所以我确信这很简单。
梗概:
在我的页面中,有几个不同的.cshtml文件,当用户点击链接时会显示这些文件。在EquipmentData.cshtml文件中,我有一个下拉列表,在更改时,ajax回发到控制器以将编辑器模板加载到div中。
在该编辑器模板(StorageTankData.cshtml)中,有一个数据列表,并有一个占位符,用于单个项目的编辑模板(StorageTank.cshtml)。初始化StorageTank.cshtml以插入新的(id为零);当用户单击数据列表中的一个项目时,我们再次调用控制器以获取该特定项目的StorageTank.cshtml局部视图,并将该html替换为编辑div。
所有这一切都很有效。在StorageTank.cshtml模板中,我有一个Ajax.Begin表单,它发布到另一个控制器操作以保存存储罐数据,然后调用相同的控制器方法来获取StorageTankData.cshtml局部视图。我们的想法是刷新项目列表并将编辑表单重置为插入模式并将其替换为div。
在IE浏览器中运行良好,但在Chrome和Firefox中,我只获得了页面上的局部视图,而不是整个页面的替换发生。我认为这是因为我的保存回发转到了与生成整个页面的方法不同的控制器方法,但我不知道该怎么做。
我在IE中看到的是URL保持在“/ Edit”(控制整个页面的动作)并且替换效果很好。在Chrome和FF中,网址会更改为我的“/ SaveStorageTank”操作。所以,我认为这解释了为什么那些浏览器在完成后只显示部分视图。我不明白的是为什么他们不继续进行替换。
在重新显示之前,我没有看到Firebug或Chrome中的错误。 (当然,他们会在$(document).ready ...中绊倒,因为部分视图没有加载jquery文件)。但是,也许我只是不知道在哪里/如何寻找这些错误。
好的,对不起长话故事。这是一些细节。
EquipmentEdit.cshtml
@model kpa.mko.bll.viewmodels.clientData.ClientDataFormViewModel
<table id="equipment">
<tr class="form-row">
<td class="form-left">Forklift On Site?</td>
<td class="form-right">
@Html.EditorFor(x => x.ForkliftOnSite)
@Html.ValidationMessageFor(x => x.ForkliftOnSite)
</td>
</tr>
<tr class="form-row">
<td class="form-left">Equipment</td>
<td class="form-right">
@Html.HiddenFor(m => m.AccountId)
Equipment Type: <select id="ddlEquipmentType">
<option value="">--select one--</option>
@foreach (var lookupValue in Model.EquipmentTypes.OrderBy(lv => lv.ShortName))
{
<option value="@lookupValue.LookupValueId">@lookupValue.ShortName</option>
}
</select>
<div id="divEquipmentEdit" style="display: none;">
</div>
</td>
</tr>
</table>
<script type="text/javascript">
$(document).ready(function () {
$("#ddlEquipmentType").change(
function () {
var selection = $("#ddlEquipmentType option:selected").text();
if (selection == "Storage Tanks") {
//Try to get the partial view of the editor template }
$.ajax({
url: '@Url.Action("LoadStorageTankDataEditor")',
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ accountId: $('#AccountId').val() }),
dataType: "html",
success: function (view) {
$('#divEquipmentEdit').show();
$('#divEquipmentEdit').html(view);
},
error: function (xhr, ajaxOptions, thrownError) {
alert('error = ' + thrownError);
alert('xhr resp text = ' + xhr.responseText);
}
});
} else {
$('#divEquipmentEdit').hide();
}
}
);
});
</script>
StorageTankData.cshtml
@model kpa.mko.bll.viewmodels.clientData.StorageTankData
@using kpa.mko.dal.Entities;
Existing Tanks:
<br /><br />
@Html.HiddenFor(m => m.AccountId)
@if (Model.StorageTanks.Count == 0)
{
<div>No tanks for this account.</div>
}
else
{
foreach (StorageTank st in Model.StorageTanks)
{
@st.ListDescription <a href="javascript:getEditor(@st.StorageTankID);">Edit</a><br />
}
}
<br /><br />
<div id="divTankEditor">
</div>
<script type="text/javascript">
$(document).ready(function () {
getEditor(0);
});
function getEditor(storageTankId) {
//Substitute in the StorageTank editor to the div above.
$.ajax({
url: '@Url.Action("LoadStorageTankEditor")',
type: "POST",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({ storageTankId: storageTankId, accountId: $('#AccountId').val() }),
dataType: "html",
success: function (view) {
$('#divTankEditor').html(view);
if (storageTankId == 0) {
$('#btnTankDelete').hide();
} else {
$('#btnTankDelete').show();
}
},
error: function (xhr, ajaxOptions, thrownError) {
alert('error = ' + thrownError);
alert('xhr resp text = ' + xhr.responseText);
}
});
}
</script>
StorageTank.cshtml
@model kpa.mko.bll.viewmodels.clientData.StorageTankForEdit
@using kpa.mko.dal.Entities;
@using kpa.mko.bll.factories;
@using (Ajax.BeginForm("SaveStorageTank", "ClientData", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "divEquipmentEdit" }))
{
@Html.HiddenFor(st => st.TankForEdit.StorageTankID)
<div>Tank Placement:@Html.DropDownListFor(m => m.PlacementSelected, Model.Placements)</div>
<div>Department: @Html.DropDownListFor(m => m.DepartmentSelected, Model.Departments)</div>
<div>Volume (gal): @Html.EditorFor(m => m.TankForEdit.VolumeInGallons)</div>
<div>Content of Tank: @Html.DropDownListFor(m => m.StorageTankContentsSelected, Model.StorageTankContents)</div>
<div>Secondary Containment? @Html.EditorFor(m => m.TankForEdit.HasSecondaryContainment)</div>
<div>If so, what type: @Html.EditorFor(m => m.TankForEdit.SecondaryContainmentType)</div>
<div>Tank Has Overfill Alarm? @Html.EditorFor(m => m.TankForEdit.HasOverfillAlarm)</div>
<div>If so, what type: @Html.EditorFor(m => m.TankForEdit.OverfillAlarmType)</div>
<input type="submit" value="Save Tank Data" name="submitButton" /> <input type="submit" value="Delete Tank" id="btnTankDelete" name="submitButton" /> <input type="button" value="Reset" onclick="getEditor(0); return false;" />
}
保存的控制器方法
public PartialViewResult SaveStorageTank(string submitButton, string accountId)
{
int acctId = int.Parse(accountId);
StorageTankForEdit stfe = new StorageTankForEdit(acctId);
if (TryUpdateModel(stfe))
{
if (!string.IsNullOrEmpty(submitButton) && submitButton.Equals("Delete Tank"))
{
//Delete the tank already.
StorageTankFactory.Delete(stfe.TankForEdit);
}
else
{
stfe.TankForEdit.DepartmentFk = int.Parse(stfe.DepartmentSelected);
stfe.TankForEdit.Placement = (StorageTankPlacement)Enum.Parse(typeof(StorageTankPlacement), stfe.PlacementSelected);
stfe.TankForEdit.StorageTankContentFk = int.Parse(stfe.StorageTankContentsSelected);
//@^*#$^ NHibernate doesn't bother to get the content class upon re-display, so we don't see the content type.
//I think it's caching this tank, so let's try populating the content here and see if it shows up.
stfe.TankForEdit.StorageTankContent = StorageTankContentFactory.GetById(stfe.TankForEdit.StorageTankContentFk);
StorageTankFactory.Save(stfe.TankForEdit);
}
}
//We decided to reset to the insert state.
return LoadStorageTankDataEditor(acctId);
获取StorageTankData部分视图的控制器方法
public PartialViewResult LoadStorageTankDataEditor(int accountId)
{
StorageTankData std = new StorageTankData(accountId);
std.StorageTanks = StorageTankFactory.GetByAccount(accountId);
return PartialView("EditorTemplates/StorageTankData", std);
}
获取StorageTank部分视图的控制器方法
public PartialViewResult LoadStorageTankEditor(int storageTankId, int accountId)
{
StorageTankForEdit st = new StorageTankForEdit(accountId);
if (storageTankId > 0)
{
st.TankForEdit = StorageTankFactory.GetById(storageTankId);
}
return PartialView("EditorTemplates/StorageTank", st);
}
答案 0 :(得分:0)
我们无法弄清楚为什么由StorageTank.cshtml中的Ajax.BeginForm完成的表单帖子无法替换部分视图。
我们所做的是将其切换为Html.BeginForm,并使用旧的jquery ajax调用将表单发布到我们的控制器。在该呼叫成功的过程中,我们手动进行了替换。
function save(){
//Substitute in the StorageTank editor to the div above.
$.ajax({
url: '@Url.Action("SaveStorageTank")',
type: "POST",
data: $('#stform').serialize(),
success: function (view) {
$('#divEquipmentEdit').html(view);
},
error: function (xhr, ajaxOptions, thrownError) {
alert('error = ' + thrownError);
alert('xhr resp text = ' + xhr.responseText);
}
});
}
所以,我们没有真正找出根本问题或为什么Ajax.BeginForm帖子不会取代Chrome和Firefox中的局部视图,而是让它使用这种方法。< / p>