简体   繁体   English

带多个提交按钮的ASP.NET MVC3剃须刀

[英]Asp.net mvc3 razor with multiple submit buttons

I'm using MVC3 Razor. 我正在使用MVC3 Razor。 I have 2 submit buttons setup on my view but the problem I'm having is that both submit buttons cause the validation of the model. 我在视图上设置了2个提交按钮,但是我遇到的问题是两个提交按钮都会导致模型验证。 I want to hook up individual submit buttons with specific input controls for validation. 我想用特定的输入控件连接各个提交按钮以进行验证。

I know this is a few months old but the solutions here seemed needlessly complex and there's no accepted answer yet. 我知道这已经几个月了,但是这里的解决方案似乎不必要地复杂,而且还没有公认的答案。 If you name your inputs the same but give them different values, you can get that value in your controller just by including a string with the name of the input as a variable. 如果您为输入命名相同但给它们提供不同的值,则只需在输入中包含一个以输入名作为变量的字符串即可在控制器中获得该值。 This is how I solved this problem: 这就是我解决此问题的方法:

View: 视图:

 <input type="submit" id="EnterprisePush" name="btnSubmit" value="Push" />
 <input type="submit" id="EnterprisePull" name="btnSubmit" value="Pull" />

Controller: 控制器:

[HttpPost]
public ActionResult EnterpriseAdmin(int id, string btnSubmit, FormCollection collection)
{
  switch (btnSubmit) {
    case "Push":
      /* Do Something here */
      break;
    case "Pull":
      /* Do Something else here */
      break;
  }

The browser is always going to submit the entire form regardless of which submit button you press. 无论您按下哪个提交按钮,浏览器都会始终提交整个表单。

The best solution would be to have two submit buttons with the same value for the name attribute and different values for the value attributes. 最好的解决方案是使两个提交按钮具有相同的name属性值和不同的value属性value

When you submit the form, the value of the button will be submitted as well. 提交表单时,按钮的值也会被提交。 In your action which handles that form submission, you check to see the value of the button and perform the correct validation based on that. 在处理该表单提交的操作中,您检查以查看按钮的值并基于该值执行正确的验证。

In your form you would have something like this: 在您的表单中,您将具有以下内容:

<button type="submit" name="Command" value="command1">Do Command #1</button>
<button type="submit" name="Command" value="command2">Do Command #2</button>

Your Form Model would look like this: 您的表单模型如下所示:

public class MyFormModel() {
    public string Command {get;set;}
    public string SomeOtherVal {get;set;}
}

Your controller\\action would look like this: 您的控制器\\动作如下所示:

public ActionResult HandleFormSubmit(MyFormModel model) {
    if (model.Command == "command1") {
        // do something
    } else if (model.Command == "command2") {
        // do something else
    }
}

Firstly, you can disable client validation on your cancel button simply by adding the CSS class 'cancel' to it. 首先,您只需在CSS取消类中添加CSS类“取消”即可禁用客户端验证。 See: Disable client-side validation in MVC 3 "cancel" submit button 请参阅: 在MVC 3“取消”提交按钮中禁用客户端验证

Secondly, as well testing the submit element's form name as described above, you can use a custom action selector. 其次,除了如上所述测试提交元素的表单名称外,您还可以使用自定义操作选择器。 Here's mine, which I originally took from the blog post shown in the comment: 这是我的,我最初来自评论中显示的博客文章:

/// <summary>
/// Used to vary an action method based on which button in a form was pressed. This
/// is useful but is an anti-pattern because it couples the controller to names
/// used in the form elements. 
/// </summary>
/// <remarks>
/// See the example at http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx
/// </remarks>
public class AcceptButtonAttribute : ActionMethodSelectorAttribute
{
    public string ButtonName { get; set; }

    public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
    {
        var req = controllerContext.RequestContext.HttpContext.Request;
        return !string.IsNullOrEmpty(req.Form[this.ButtonName]);
    }
}

In your controller: 在您的控制器中:

    [HttpPost]
    [ActionName("Edit")]
    [AcceptButton(ButtonName = "Cancel")]
    public ActionResult Edit_Cancel(MyModel model)
    {
        return RedirectToAction("Index");
    }

    [HttpPost]
    [AcceptButton(ButtonName = "Save")]
    public ActionResult Edit(MyModel model)
    {
        // do real work here
    }

Note that you need the [ActionName("Edit")] attribute to tell MVC that although using a different method name, it is for the Edit action. 请注意,您需要[ActionName(“ Edit”)]属性来告知MVC,尽管使用了不同的方法名称,但它是用于Edit操作的。

And in your View: 在您看来:

    <input type="submit" name="Save" value="Save" />
    <input type="submit" name="Cancel" value="Cancel" class="cancel" />

My solution was to do two things. 我的解决方案是做两件事。 Say we have a Save button and another Add Something button. 假设我们有一个“保存”按钮和另一个“添加内容”按钮。 When user clicks on Save we want client validation and server validation to be performed. 当用户单击“保存”时,我们希望执行客户端验证和服务器验证。 For later button we don't want any validation to take place. 对于以后的按钮,我们不希望进行任何验证。

  1. Temporarily disable client validation for second button (on click): 暂时禁用第二个按钮(单击时)的客户端验证:

<input type="submit" name="submit-button" value="Save" /> <input type =“ submit” name =“提交按钮” value =“保存” />

<input type="submit" name="submit-button" value="Add Something" onclick="document.forms[0].noValidate = true; document.forms[0].submit();" <input type =“ submit” name =“提交按钮” value =“添加内容” onclick =“ document.forms [0] .noValidate = true; document.forms [0] .submit();” /> />

Good thing about it is when JavaScript is disabled the client validation would never have taken place anyway. 这样做的好处是,当禁用JavaScript时,客户端验证将永远不会进行。

  1. Take care of server side 照顾服务器端

Similar to what Bryan is saying when you click any submit button within a form, the entire form and the clicked submit button value is posted. 类似于Bryan在单击表单中的任何提交按钮时所说的那样,整个表单和单击的提交按钮值都会发布。 You can differentiate which button was clicked by the name posted. 您可以通过发布的名称来区分单击了哪个按钮。 In example above when user clicks on Save button and we read Request.Form["submit-button"] in controller post action we get "Save". 在上面的示例中,当用户单击“保存”按钮,并且在控制器发布操作中读取了Request.Form [“ submit-button”]时,我们得到了“保存”。 If user clicked on Add Something we would get "Add Something". 如果用户单击“添加内容”,我们将获得“添加内容”。 This is the way HTML is supposed to work. 这就是HTML应该起作用的方式。

Now to get around having magic strings all over the place I usually have a public static class within the controller, like so: 现在到处都是魔术字符串,我通常在控制器内有一个公共静态类,如下所示:

public class HomeController
{
    public static class Buttons
    {
        public const string Save = "Save";
        public const string AddSomething = "Add something";
    }
    // Action methods
}

So you can use these for rendering form: 因此,您可以将这些用于呈现表单:

&lt;input type="submit" name="submit-button" value="@HomeController.Buttons.Save" /&gt;

And you can easily read the button clicked in controller: 您可以轻松阅读控制器中单击的按钮:

[HttpPost]
public ActionResult Index(Model viewModel)
{
    var buttonClicked = Request.Form["submit-button"];
    switch (buttonClicked) {
        case HomeController.Buttons.Save:
            return Save(viewModel);
        case HomeController.Buttons.AddSomething:
            return AddSOmething(viewModel);
    }
    return View();
}

In Save method you first ask if ModelState.IsValid and return view model if not but in AddSomething method we will clear any errors: 在Save方法中,您首先询问是否为ModelState.IsValid,如果不是,则返回视图模型,但在AddSomething方法中,我们将清除所有错误:

public ActionResult AddSomething(Model viewModel)
{
    ModelState.Clear();
    // your code to add something to model
    return View(viewModel);
}

This was you keep everything clean, tidy and testable. 这是您保持一切清洁,整洁和可测试的方式。 And you can introduce a constant for submit-button html name attribute. 您可以为Submit-button html name属性引入一个常量。 It might be possible to do all the constants with T4MVC too. 也可以使用T4MVC来完成所有常量。 A similar solution applies to when you need a "auto postback" combo box, except you need a hidden field that is set via onchange event of the select element. 当您需要“自动回发”组合框时,类似的解决方案适用于您需要通过select元素的onchange事件设置的隐藏字段的情况。

Hope this helps. 希望这可以帮助。

Just use this code as a template: 只需使用以下代码作为模板:

@{
    var nextButtonVal = "Next >>";
    var backButtonVal = "<< Back";
    if (IsPost) {
      if(Request["navigate"].Equals(backButtonVal)){Response.Redirect("~/pageFoo");}
      if(Request["navigate"].Equals(nextButtonVal)){Response.Redirect("~/pagebar");}
    }
}

<input type="submit" value="@backButtonVal" title="Back" name="navigate"/>
<input type="submit" value="@nextButtonVal" title="Next" name="navigate"/>

One final thing I would do is instead of using intelligent strings, use an enum to determine the value for each input tag. 我要做的最后一件事是代替使用智能字符串,而使用enum来确定每个输入标签的值。 Using razor syntax: 使用剃刀语法:

@Enum.GetName(typeof(YourEnumType), yourEnum.WhateverValue)

then in your controller: 然后在您的控制器中:

public ActionResult DoSomethingBasedOnEnumValue(string enumValue)
{
    YourEnumType localVar = (YourEnumType)Enum.Parse(typeof(YourEnumType), enumValue);

    switch(localVar)
    {
        case YourEnumType.Action1:
            //do something
            break;

        case YourEnumType.Action2:
            //do something else
            break;
    }
    return View();
}

If you want to have separate action for delete, try this. 如果要对删除执行单独的操作,请尝试此操作。

add a delete action in the controller and mark it as HttpDelete , 在控制器中添加删除动作并将其标记为HttpDelete

[HttpDelete]
public ActionResult Edit(int id, string foo) {
   ...
}

And in the view, button name should be X-HTTP-Method-Override and value should be DELETE 并且在视图中,按钮名称应为X-HTTP-Method-Override ,值应为DELETE

<button name="X-HTTP-Method-Override" value="DELETE" formnovalidate="formnovalidate" class="cancel">Delete</button>

note: all most all the browsers don't allow for other HTTP methods, like HEAD, PUT, or DELETE. 注意:大多数浏览器都不允许使用其他HTTP方法,例如HEAD,PUT或DELETE。 but by add a header to the HTTP request, X-HTTP-Method-Override , that is supposed to be interpreted by the service and acted upon regardless of the actual HTTP method used. 但可以通过向HTTP请求中添加标头X-HTTP-Method-Override ,该标头应由服务解释并采取行动,而与实际使用的HTTP方法无关。 So above code will add a header to the request like X-HTTP-Method-Override: DELETE . 因此,以上代码将为请求添加标头,例如X-HTTP-Method-Override: DELETE and .net framework will do the rest of the things and direct you to delete action. .net框架将完成其余所有工作,并指示您删除操作。

如果在这种情况下,您将全部使用[Remote]属性作为验证模型属性,则提交按钮名称不会出现在服务器端。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM