jquery - 具有多格式 View 的MVC 3中的Ajax发布

标签 jquery ajax asp.net-mvc-3 c#-4.0 razor

我删除了与该主题相关的先前问题,因为上下文有所变化,并且问题是新的。

我现在只有一个视图,只有一个模型。该视图有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)即使我可以正确地发布模型以便有搜索值,如何将数据返回到网格,以及当验证失败而不是将结果发送到UpdateTargetID时如何显示模型错误?

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;
    }


如何获得有关aj​​ax帖子的模型以使其生效?以及如何找回合适的模型以使网格具有结果?如果出现错误,如何以与validationsummary类似的方式显示该错误?

更新:对于@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);
        }
    });
});


我也尝试使用data:省略了上面的行,它将击中我的控制器动作,但是再次发送的模型在属性中具有空值。该模型不是null,而只是属性值。我在模型的下拉列表属性中确实有值,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"})) {


我认为此问题是由于以下事实引起的:我的视图是通过单击控制器的Search操作来呈现的,因此URL为/ Admin / Search,但是视图上的表单需要发布到/ Admin / FilterByUserData和/ Admin / FilterByEntityData 。就像我上面说的,如果我使用正确的签名显式创建Html.BeginFrom,那么它可以工作,但是它不是Ajax

更新3

@Shyju

我得到它的解决,问题肯定是Form签名,我对其进行了修改,可以成功地执行我的控制器操作,并且还可以传递数据!感谢你的帮助!

这是它起作用的原因:

@using (Html.BeginForm(new {id = "SearchByUserForm", @controller = "Admin", @action = "FilterByUserData"})) {

最佳答案

在jquery帖子中传递数据时,请使用与属性名称相同的名称(作为操作方法的参数的viewmodel)。您将在那里得到充满数据的对象。

('form').submit(function () {
    $.post('@Url.Action("Logon","Account")', { LastName : $("#username").val(), 
                     UserName:   $("#password").val() },
                     EmailAddress:   $("#password").val() },  function (data) {

    //process the result and update the grid

});


编辑:由于OP说,它不能正常工作,我从头开始创建一个示例项目,以验证这一点,并且工作正常。
这是我的观点

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>

<h2>Index</h2>
<form id="frm1" action="Search">
LastName <input type="text" id="LastName" /><br />
UserName <input type="text" id="UserName" /><br />
Email Address <input type="text" id="EmailAddress" />
<input type="submit" value="go" />
</form>
<script type="text/javascript">
    $(function () {
        $('#frm1').submit(function () {
            $.post('@Url.Action("Search", "Home")', { LastName: $("#LastName").val(),
                UserName: $("#UserName").val(),
                EmailAddress: $("#EmailAddress").val()
            }, function (data) {

                alert(data)
            });
            return false;
        });
    });
</script>


我收到接听电话的操作方法是

public ActionResult Search(SearchUsersViewModel objVM)
{
   return View();
}


这是结果的屏幕截图

客户



控制器动作方法



您甚至还可以使用jquery serialize()方法将表单发送到控制器操作。

http://api.jquery.com/serialize/

关于jquery - 具有多格式 View 的MVC 3中的Ajax发布,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9999703/

相关文章:

c# - EF 4 和 POCO 的最佳实践/入门解决方案

php - 当我在键盘上按下 Enter 时,它会在不通过 javascript 的情况下提交表单?

javascript - MVC3,同一个页面View之间的切换

javascript - 在主干中启用 CORS

javascript - 通过 ajax 调用将 Html 字符串从 View 传递到 Controller

javascript - Angular:在 AJAX 成功时设置变量

asp.net-mvc - 为什么 Asp.NET MVC 优于 Asp.NET Web 窗体

javascript - 为什么 select 的选定值会在动态下拉列表中发生变化?

JavaScript/Jquery 文件未加载

entity-framework - 我看不到带有 POCO 类的 DbContext 中的存储过程