【发布时间】:2012-04-03 19:05:35
【问题描述】:
我删除了我之前处理该主题的问题,因为上下文发生了一些变化并且问题是新的。
我现在只有一个视图,只有一个模型。该视图有 2 种形式。每个表单提交自己的操作,每个操作使用模型数据的子集,使用数据执行搜索。然后将搜索结果添加到模型的属性中,并需要将其呈现回视图。我可以通过一个标准的 html 帖子来完成这一切,但现在这需要是一个 ajax 帖子。
这是我的 ViewModel:
public sealed class SearchUsersViewModel {
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "Username")]
public string Username { get; set; }
[Display(Name = "Email Address")]
public string EmailAddress { get; set; }
[Display(Name = "Entity Type")]
public byte EntityTypeID { get; set; }
[Display(Name = "Search Name")]
public string SearchField { get; set; }
public IEnumerable<SelectListDTO> EntityTypes { get; set; }
public IEnumerable<UserEditViewModel> Users { get; set; }
[Display(Name = "Total Rows")]
public int TotalRowCount { get; internal set; }
public SearchUsersViewModel() {
EntityTypes = LookupEntityTypeService.Instance.SelectList;
Users = new List<UserEditViewModel>();
}
}
这是我的观点:
@model SearchUsersViewModel
<div>
<div class="SearchByUserDataTable">
@using (Html.BeginForm("FilterByUserData", "Admin", FormMethod.Post, new {model = Model})) {
@Html.ValidationSummary(true)
<table cellpadding="0" cellspacing="0" border="0">
<tr style="height: 30px;">
<td class="Header01">
User Search:
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" border="0">
<tr style="height: 20px;">
<td class="Header02">
Search By User Information:
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" border="0">
<tr style="height: 1px;">
<td class="ContentDividerHoriz_425"></td>
</tr>
</table>
<table id="searchByUserDataTable" cellpadding="0" cellspacing="0" border="0">
<tr style="height: 26px;">
<td class="leftColumn">
@Html.LabelFor(model => model.LastName):
</td>
<td class="rightColumn">
@Html.TextBoxFor(model => model.LastName, new { id = "lastNameSearchField", @class = "TextField_220" })
</td>
</tr>
<tr style="height: 26px;">
<td class="leftColumn">
@Html.LabelFor(model => model.Username):
</td>
<td class="rightColumn">
@Html.TextBoxFor(model => model.Username, new { id = "userNameSearchField", @class = "TextField_220" })
</td>
</tr>
<tr style="height: 26px;">
<td class="leftColumn">
@Html.LabelFor(model => model.EmailAddress):
</td>
<td class="rightColumn">
@Html.TextBoxFor(model => model.EmailAddress, new { id = "emailAddressSearchField", @class = "TextField_220" })
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td id="filterByUserError" style="width: 375px;"></td>
<td align="right" style="width: 50px; padding-right: 75px;">
<div>
<input id="filterByUserButton" type="submit" value="Search" />
</div>
</td>
</tr>
</table>
}
</div>
<div class="SearchByEntityDataTable">
@using (Html.BeginForm("FilterByEntityData", "Admin", FormMethod.Post, new { model = Model })) {
<table cellpadding="0" cellspacing="0" border="0">
<tr style="height: 28px;">
<td style="width: 425px;"></td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" border="0">
<tr style="height: 20px;">
<td class="Header02">
Search By Entity Information:
</td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" border="0">
<tr style="height: 1px;">
<td class="ContentDividerHoriz_425"></td>
</tr>
</table>
<table id="searchByEntityDataTable" cellpadding="0" cellspacing="0" border="0">
<tr style="height: 26px;">
<td class="leftColumn">
@Html.LabelFor(model => model.EntityTypeID):
</td>
<td class="rightColumn">
@Html.DropDownListFor(model => model.EntityTypeID, new SelectList(Model.EntityTypes, "ID", "Name"), new { id = "entityTypeDropDown", @class = "DropDown_220" })
</td>
</tr>
<tr style="height: 26px;">
<td class="leftColumn">
@Html.LabelFor(model => model.SearchField, new { id = "entityTypeSearchLabel"}):
</td>
<td class="rightColumn">
@Html.TextBoxFor(model => model.SearchField, new { id = "entityTypeSearchField", @class = "ui-widget TextField_220" })
</td>
</tr>
<tr style="height: 26px;">
<td class="leftColumn"></td>
<td class="rightColumn"></td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td id="filterByEntityError" style="width: 375px;"></td>
<td align="right" style="width: 50px; padding-right: 75px;">
<div>
<input type="submit" value="Search" />
</div>
</td>
</tr>
</table>
}
</div>
<div id="searchResults">
@(Html.Telerik().Grid(Model.Users)
.Name("Users").TableHtmlAttributes(new { style = "width: 870px;"})
.Columns(columns => {
columns.Bound(o => o.EntityTypeName).Title("Entity Type");
columns.Bound(o => o.FirstName).Title("First Name");
columns.Bound(o => o.LastName).Title("Last Name");
columns.Bound(o => o.Username).Title("Username");
columns.Template(
@<text>
<a href="mailto:@item.EmailAddress" target="blank">@item.EmailAddress</a>
</text>).Title("Email").HtmlAttributes(new { style = "text-align: center" }).HeaderHtmlAttributes(new { style = "text-align: center" });
columns.Template(
@<text>
<div class="ActionIcon_ResendInvitationOn" title="Resend Invitation" onclick="location.href='@Url.Action("ResendInvitation", "Admin", new { entityTypeID = item.EntityTypeID, emailAddress = item.EmailAddress })'"></div>
@{
if (item.IsApproved) {
<div class="ActionIcon_AccountStatusOn" title="Disable Account" onclick="setApprovalStatus('@item.Username', false);"></div>
}
else {
<div class="ActionIcon_AccountStatusOn" title="Enable Account" onclick="setApprovalStatus('@item.Username', true);"></div>
}
}
@{
if (item.IsLockedOut) {
<div class="ActionIcon_ResetPasswordOn" title="Unlock Account" onclick="unlockAccount('@item.Username')"></div>
}
<div class="ActionIcon_ResetPasswordOn" title="Reset Password" onclick="resetPassword('@item.Username')"></div>
}
<div class="ActionIcon_EditOn" title="Edit User" onclick="location.href='@Url.Action("Edit", "Admin", new { id = item.MembershipID, username = item.Username })'"></div>
</text>).Title("Actions");
columns.Bound(o => o.RowNumber).Hidden(true);
columns.Bound(o => o.MembershipID).Hidden(true);
columns.Bound(o => o.EntityTypeID).Hidden(true);
})
.Pageable(paging => paging.PageSize(10))
.Sortable()
)
<span>Total Rows: </span> @Html.DisplayFor(model => Model.TotalRowCount)
<p>
@Html.ActionLink("Create New User", "Create", "Invitation")
</p>
</div>
</div>
我已将此视图与这一行一起用作 BeginForm:
@using (Html.BeginForm("FilterByUserData", "Admin", FormMethod.Post, new {model = Model}))
然后使用这个:
@using (Html.BeginForm())
使用这个 Ajax 脚本
$('#filterByUserButton').click(function () {
$.ajax({
url: '/Admin/FilterByUserData',
type: 'POST',
success: function (result) {
alert(result);
}
});
});
第一种方法使用 HTML 后效果很好,但我需要使用 ajax 功能,所以第二种方法是我的麻烦
1) 使用 ajax 调用,发布到操作的模型包含文本字段中的所有 Null 值,而不是我在表单中输入的值。该模型使用 HTML 方法可以正常发布
2) 即使我可以让模型正确发布以便我可以搜索值,我如何将数据返回到网格以及如何在验证失败时显示模型错误而不是将结果发送到更新目标 ID?
3) 能够让两个表单都提交给控制器,并将相同的结果返回给视图,即搜索结果
似乎我只能有 1 个 UpdateTarget - 如果您从来没有错误,这很好......但行为很糟糕,我需要在字段上显示验证错误,就像这是一个同步调用一样。所以来自动作的错误结果需要有它自己的目标。
我想出了这个 Ajax 调用,它可以很好地处理不需要返回数据的操作,只需返回成功或错误消息。每个都加载到自己的 div 中。
$(function () {
$('form').submit(function () {
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.toString().indexOf("Success") == -1) {
$('#successDiv').hide();
$('#errorDiv').html('');
$('#errorDiv').fadeIn(100).append($('<ul />').append(result));
}
else {
$('#errorDiv').hide();
$('#successDiv').fadeIn(1000).html(result).fadeOut(6000);
}
}
});
}
return false;
});
});
这些是处理搜索的操作(FilterByUserData 操作不同,因为我试图弄清楚如何返回正确的结果,但我还没有让它正确返回数据。
public ActionResult Search() {
var model = new SearchUsersViewModel();
return View(model);
}
[HttpPost]
public ActionResult FilterByUserData(SearchUsersViewModel model) {
var result = string.Empty;
if (model.LastName != null || model.Username != null || model.EmailAddress != null) {
var listOfMatchingUsers = SearchUserService.SearchByUserData(model.LastName, model.Username, model.EmailAddress);
model = PrepareResultsModel(listOfMatchingUsers, model);
}
else {
ModelState.AddModelError("", "Last Name, Username or Email Address must be entered for search");
}
if (ModelState.IsValid)
result = "Success: Thanks for your submission: " + model.Username;
else {
result = ModelState.SelectMany(item => item.Value.Errors).Aggregate(result, (current, error) => current + error.ErrorMessage);
}
return Content(result, "text/html");
}
[HttpPost]
public ActionResult FilterByEntityData(SearchUsersViewModel model) {
if(model.EntityTypeID > 0 && model.SearchField != null) {
var listOfMatchingUsers = SearchUserService.SearchByEntityData(model.EntityTypeID, model.SearchField);
model = PrepareResultsModel(listOfMatchingUsers, model);
}
else {
var entityType = string.Empty;
if(model.EntityTypeID == 2) entityType = "Lender";
if (model.EntityTypeID == 3) entityType = "School";
ModelState.AddModelError("", entityType + " name must be entered for search");
}
return View("Search", model);
}
private SearchUsersViewModel PrepareResultsModel(ICollection<SearchUserResultsDTO> listOfMatchingUsers, SearchUsersViewModel model) {
if (listOfMatchingUsers.Count != 0) {
model.Users = listOfMatchingUsers.Select(item => new UserEditViewModel(item)).ToList();
model.TotalRowCount = model.Users.Count();
}
return model;
}
如何获取 ajax 帖子的模型以执行我的操作?以及如何获得正确的模型,以便我的网格有结果?如果出现错误,如何以与验证摘要类似的方式显示?
更新:@Shyju 我尝试了您建议的尝试将您的示例合并到我的代码中,但模型属性的值仍然为空并且没有被设置。这是我在我的 ajax 函数中所做的,注意它与你的 form.post 方法不同:
$('#filterByUserButton').click(function () {
$.ajax({
url: '/Admin/FilterByUserData',
type: 'POST',
data: {LastName : $('#LastName').val(), Username : $('#Username').val(), EmailAddress : $('#EmailAddress').val()},
success: function (result) {
processResult(result);
}
});
});
我也试过这个:
$('form').submit(function() {
alert("submitting");
$.post('@Url.Action("FilterByUserData","Admin")', { LastName: $("#LastName").val(), UserName: $("#Username").val(), EmailAddress: $("#EmailAddress").val() },
function(data) {
alert(data);
});
});
页面闪烁并且第一个警报是它,但它从未命中第二个警报并且从未命中控制器,因此它看起来甚至没有真正发布。 我也试过这个,但它也没有击中控制器动作:
$('#filterByUserButton').click(function () {
alert("submitting");
$.ajax({
url: '/Admin/FilterByUserData',
type: 'POST',
data: {LastName : $('#LastName').val(), Username : $('#Username').val(), EmailAddress : $('#EmailAddress').val()},
success: function (result) {
alert(result);
processResult(result);
}
});
});
我也尝试了上面的数据:省略行,它会影响我的控制器操作,但同样,正在发送的模型在属性中具有空值。模型不是空的,只是属性值。我在模型的下拉列表属性中有值,EntityTypes 仍然显示 4 个值。所以有一些关于发布该表单的事情,但表单值没有进入模型属性。
更新 2
@Shyju 我正在使用你的 ajax 代码:
$(function () {
$('#SearchByUserForm').submit(function () {
$.post('@Url.Action("FilterByUserData", "Admin")', { LastName: $("#LastName").val(), UserName: $("#UserName").val(), EmailAddress: $("#EmailAddress").val() },
function (data) {
alert(data);
});
return false;
});
});
我可以在点击提交按钮后逐步执行此操作,但它无法点击我的控制器的发布操作。我查看了为表单呈现的 HTML,这就是我所看到的......这是不正确的:
<form action="/Admin/Search/SearchByUserForm" method="post">
如您所见,此处的 POST 操作是错误的。控制器是正确的,但其余的都是错误的。它应该发布到 /Admin/FilterByUserData。我确定这只是我所处的语法混乱,我只是不确定我做错了什么。在标准形式中,我会这样做:
@using (Html.BeginForm("FilterByUserData", "Admin", FormMethod.Post, new { model = Model })) {
哪个工作正常。但是我不能将此表单签名与您的 Ajax 代码中的 URL 操作帖子结合起来。我尝试只用 ID 留下表格,但我遇到了上面所说的问题:
@using (Html.BeginForm(new {@id = "SearchByUserForm"})) {
我认为这个问题是由于我的视图是通过点击控制器的搜索操作来呈现的,所以 URL 是 /Admin/Search 但视图上的表单需要发布到 /Admin/FilterByUserData 和 /管理员/FilterByEntityData。就像我上面说的,如果我用正确的签名明确地创建 Html.BeginFrom ,那么它就可以工作,但它不是 Ajax
更新 3
@Shyju
我搞定了,问题肯定是表单签名,我修改了它,我可以成功地点击我的控制器操作,并且数据正在传入!感谢您的所有帮助!
这就是它的工作原理:
@using (Html.BeginForm(new {id = "SearchByUserForm", @controller = "Admin", @action = "FilterByUserData"})) {
【问题讨论】:
标签: jquery ajax asp.net-mvc-3 c#-4.0 razor