asp.net mvc 多个提交按钮

 原文:http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx

UPDATE 2012-07-19

另外一篇文章有更多改进的方法

http://www.cnblogs.com/wuchang/archive/2010/01/29/1658916.html

适用场景:

      假如你要设计一个注册页面,上面有几个填写注册信息的textbox,一个用于提交注册信息的按钮和一个用于返回首页的按钮

可有如下选择方案:

  方案1:每个按钮都会提交表单,但给按钮分配不同的value,用于逻辑中进行判断提交事件由谁触发

~/Views/Account/Register.aspx

  1: <% using (Html.BeginForm()) { %>
  2:     <div>
  3:         <fieldset>
  4:             <legend>Account Information</legend>
  5:             <p>
  6:                 <label for="username">Username:</label>
  7:                 <%= Html.TextBox("username") %>
  8:                 <%= Html.ValidationMessage("username") %>
  9:             </p>
 10:             <p>
 11:                 <label for="email">Email:</label>
 12:                 <%= Html.TextBox("email") %>
 13:                 <%= Html.ValidationMessage("email") %>
 14:             </p>
 15:             <p>
 16:                 <label for="password">Password:</label>
 17:                 <%= Html.Password("password") %>
 18:                 <%= Html.ValidationMessage("password") %>
 19:             </p>
 20:             <p>
 21:                 <label for="confirmPassword">Confirm password:</label>
 22:                 <%= Html.Password("confirmPassword") %>
 23:                 <%= Html.ValidationMessage("confirmPassword") %>
 24:             </p>
 25:                 <button name="button" value="register">Register</button>
 26:                 <button name="button" value="cancel">Cancel</button>
 27:             </p>
 28:         </fieldset>
 29:     </div>
 30:  <% } %>

~/Controllers/AccountController.cs

  1: [AcceptVerbs(HttpVerbs.Post)]
  2: public ActionResult Register(string button, string userName, string email, string password, string confirmPassword)
  3: {
  4:     if (button == "cancel")
  5:         return RedirectToAction("Index", "Home");
  6: 
  7:     ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
  8: 
  9:     if (ValidateRegistration(userName, email, password, confirmPassword))
 10:     {
 11:         // Attempt to register the user
 12:         MembershipCreateStatus createStatus = MembershipService.CreateUser(userName, password, email);
 13: 
 14:         if (createStatus == MembershipCreateStatus.Success)
 15:         {
 16:             FormsAuth.SignIn(userName, false /* createPersistentCookie */);
 17:             return RedirectToAction("Index", "Home");
 18:         }
 19:         else
 20:         {
 21:             ModelState.AddModelError("_FORM", ErrorCodeToString(createStatus));
 22:         }
 23:     }
 24: 
 25:     // If we got this far, something failed, redisplay form
 26:     return View();
 27: }

这个方案的副作用就是你不得不在controller添加条件判断的逻辑,并且两个按钮都提交表单内容然后由服务端进行判断跳转。

为了让controller看起来稍微那么优雅点儿,可以通过自定义ActionMethodSelectorAttribute的方法实现,如下:

  1: public class AcceptParameterAttribute : ActionMethodSelectorAttribute
  2: {
  3:     public string Name { get; set; }
  4:     public string Value { get; set; }
  5: 
  6:     public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
  7:     {
  8:         var req = controllerContext.RequestContext.HttpContext.Request;
  9:         return req.Form[this.Name] == this.Value;
 10:     }
 11: }
 12: 

Now I can split into two action methods like this:

  1: [ActionName("Register")]
  2: [AcceptVerbs(HttpVerbs.Post)]
  3: [AcceptParameter(Name="button", Value="cancel")]
  4: public ActionResult Register_Cancel()
  5: {
  6:     return RedirectToAction("Index", "Home");
  7: }
  8: 
  9: [AcceptVerbs(HttpVerbs.Post)]
 10: [AcceptParameter(Name="button", Value="register")]
 11: public ActionResult Register(string userName, string email, string password, string confirmPassword)
 12: {
 13:   // process registration
 14: }

同样,这个也不是最有效的方法,但它毕竟让你用两个controller的方法分别响应两个不同的按钮

方案2:另一个form

  1: <% using (Html.BeginForm()) { %>
  2:     <div>
  3:         <fieldset>
  4:             <legend>Account Information</legend>
  5:             <p>
  6:                 <label for="username">Username:</label>
  7:                 <%= Html.TextBox("username") %>
  8:                 <%= Html.ValidationMessage("username") %>
  9:             </p>
 10:             <p>
 11:                 <label for="email">Email:</label>
 12:                 <%= Html.TextBox("email") %>
 13:                 <%= Html.ValidationMessage("email") %>
 14:             </p>
 15:             <p>
 16:                 <label for="password">Password:</label>
 17:                 <%= Html.Password("password") %>
 18:                 <%= Html.ValidationMessage("password") %>
 19:             </p>
 20:             <p>
 21:                 <label for="confirmPassword">Confirm password:</label>
 22:                 <%= Html.Password("confirmPassword") %>
 23:                 <%= Html.ValidationMessage("confirmPassword") %>
 24:             </p>
 25:             <p>
 26:                 <button name="button">Register</button>
 27:                 <button name="button" type="button" onclick="$('#cancelForm').submit()">Cancel</button>
 28:             </p>
 29:         </fieldset>
 30:     </div>
 31: <% } %>
 32: <% using (Html.BeginForm("Register_Cancel", "Account", FormMethod.Post, new { id="cancelForm" })) {} %>
 33: 

我所做的就是在注册表单下面添加一个新的form,表单提交内容的处理指向另外一个action方法;然后将取消按钮(cancel)的type设为"button",这样就可以通过为这个按钮添加一个onclick的客户端事件(使用jQuery)提交另外一个表单(cancelForm)。这个方法比第一个更有效率,它不会提交注册表单中的内容,但它依然不是最有效率的方案,因为它同样使用服务端控制跳转。

方案3:全部使用客户端脚本

  1: <p>
  2:     <button name="button">Register</button>
  3:     <button name="button" type="button" onclick="document.location.href=$('#cancelUrl').attr('href')">Cancel</button>
  4:     <a id="cancelUrl" href="<%= Html.AttributeEncode(Url.Action("Index", "Home")) %>" style="display:none;"></a>
  5: </p>

这是处理cancel按钮的最有效的方式,这里没有同服务端进行交互以便获得跳转的url。我在这里放了一个隐藏(display:none)的有url的<a>锚链,使用button配合客户端脚本,即可实现;如果把隐藏的<a>显示出来替代cancel按钮,同样可以实现。其实现原理是通过将<a>伪装成button在客户端进行跳转。

结论:

 当我设计MVC应用时,有一个参考标准来选择什么样类型的button

  • 如果button用于提交本身所在的表单,如 “Save”, “Update”, “Ok”, “Submit” ,那就用标准的button(<button/>)
  • 如果button需要提交一些数据到服务端,如 “Delete” ,那就使用type="button"的button同时配合onclick客户端事件提交指定的form表单,详细见文章上述部分
  • 如果button只是用来导航跳转,如 “Cancel”, “Back”, “Next”, “Prev” ,那就使用<a>来替代(把a装饰成button的样子),或者使用button配合脚本进行简单的跳转处理
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值