2012-04-03 57 views
2

我删除了我之前处理主题的问题,因为上下文发生了一些变化,问题是新的。MVC 3中的Ajax帖子与多表单视图

我现在只有一个视图,只有一个模型。该视图有两种形式。每个表单都提交自己的操作,每个操作使用模型数据的子集,使用数据执行搜索。然后,搜索结果将被添加到模型的属性中,并且需要重新呈现给视图。我能够通过标准的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()) 

与此阿贾克斯脚本

$('#filterByUserButton').click(function() { 
    $.ajax({ 
     url: '/Admin/FilterByUserData', 
     type: 'POST', 
     success: function (result) { 
      alert(result); 
     } 
    }); 
}); 

随着使用HTML后能正常工作的第一种方法,但我需要使用AJAX功能,因此第二个方法是我的麻烦

1)使用Ajax调用发布到操作的模型包含文本字段中的所有空值,而不是我在表单中输入的值。 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; 
    } 

如何获取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); 
     } 
    }); 
}); 

我也尝试了上面的数据:省略行,它会打我的控制器动作,但再次被送到该模型具有空值在属性中。该模型不是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"})) { 

我觉得这个问题涉及有关从我的观点是打我的控制器的搜索行为呈现的事实,因此URL是/ Admin/Search,但视图上的表单需要发布到/ Admin/FilterByUserData和/ Admin/FilterByEntityData。就像我上面,如果我明确地创建具有正确的签名,然后它工作的Html.BeginFrom说,,但它只是不阿贾克斯

更新3

@Shyju

我得到它的工作中,问题肯定是Form签名,我修改了它,并且我可以成功地打开我的控制器操作,并且数据也被传入!感谢你的帮助!

这是得到它的工作:

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

回答

2

使用相同的名称属性名(您的视图模型中的哪一个动作方法的参数),当你在你的jQuery后传递数据。你会得到填充数据的对象。

('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 

}); 

编辑:由于运说,它不工作,我创建了一个从无到有的样本项目,以验证这一点,它是工作的罚款。 这里是我的看法貌似接收后调用

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

这里是结果

客户

enter image description here的截图

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

而我的操作方法

控制器动作方法

enter image description here

可以甚至发送的形式使用jQuery的serialize()方法,以及所述控制器的操作。

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

+0

我试图将您的建议,但它不工作,看我更新的问题 – 2012-04-03 20:27:58

+0

@CDSmith的结尾:我我的答案更新了屏幕截图, – Shyju 2012-04-03 21:32:46

+0

感谢您抽出宝贵时间来帮助和扩大你的答案。不幸的是它仍然不适合我。我的观点和形式以及张贴的路线比您的示例稍微复杂一些。我最后更新了我的问题,并结合了您的代码,并解释了为什么我的失败。 – 2012-04-04 11:56:27