asp.net mvc 多個提交按鈕

適用場景:

      假如你要設計一個註冊頁面,上面有幾個填寫註冊信息的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配合腳本進行簡單的跳轉處理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章