我正在使用MVC3 Razor。我在我的视图上设置了2个提交按钮,但我遇到的问题是两个提交按钮都会导致模型的验证。我想将具有特定输入控件的单个提交按钮连接起来进行验证。
答案 0 :(得分:64)
我知道这已经有几个月了,但是这里的解决方案似乎不必要复杂,而且还没有接受的答案。如果您将输入命名为相同但为它们指定不同的值,则只需在输入中包含一个输入名称作为变量的字符串即可在控制器中获取该值。这就是我解决这个问题的方法:
查看:
<input type="submit" id="EnterprisePush" name="btnSubmit" value="Push" />
<input type="submit" id="EnterprisePull" name="btnSubmit" value="Pull" />
控制器:
[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;
}
答案 1 :(得分:30)
无论您按哪个提交按钮,浏览器总是会提交整个表单。
最好的解决方案是让两个提交按钮具有相同的name
属性值和value
属性的不同值。
提交表单时,也会提交按钮的值。在处理表单提交的操作中,您检查按钮的值并根据该值执行正确的验证。
在你的表格中你会有这样的东西:
<button type="submit" name="Command" value="command1">Do Command #1</button>
<button type="submit" name="Command" value="command2">Do Command #2</button>
您的表单模型如下所示:
public class MyFormModel() {
public string Command {get;set;}
public string SomeOtherVal {get;set;}
}
你的控制器\动作将如下所示:
public ActionResult HandleFormSubmit(MyFormModel model) {
if (model.Command == "command1") {
// do something
} else if (model.Command == "command2") {
// do something else
}
}
答案 2 :(得分:21)
首先,您可以通过添加CSS类“取消”来取消取消按钮上的客户端验证。请参阅:Disable client-side validation in MVC 3 "cancel" submit button
其次,如上所述测试提交元素的表单名称,您可以使用自定义操作选择器。这是我的,我最初从评论中显示的博客文章中获取:
/// <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]);
}
}
在您的控制器中:
[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
}
请注意,您需要[ActionName(“Edit”)]属性告诉MVC虽然使用了不同的方法名称,但它适用于编辑操作。
在你的观点中:
<input type="submit" name="Save" value="Save" />
<input type="submit" name="Cancel" value="Cancel" class="cancel" />
答案 3 :(得分:3)
我的解决方案是做两件事。假设我们有一个Save按钮和另一个Add Something按钮。当用户单击“保存”时,我们希望执行客户端验证和服务器验证。对于以后的按钮,我们不希望进行任何验证。
&lt; input type =“submit”name =“submit-button”value =“Save”/&gt;
&lt; input type =“submit”name =“submit-button”value =“Add Something”onclick =“document.forms [0] .noValidate = true; document.forms [0] .submit();” /&GT;
好消息是,当禁用JavaScript时,无论如何都不会进行客户端验证。
类似于Bryan在单击表单中的任何提交按钮时所说的内容,将发布整个表单和单击的提交按钮值。您可以区分所发布名称单击的按钮。在上面的示例中,当用户单击“保存”按钮并且我们在控制器发布操作中读取Request.Form [“submit-button”]时,我们得到“保存”。如果用户点击Add Something,我们会得到“Add Something”。这就是HTML的工作方式。
现在为了到处都有魔术字符串,我通常在控制器中有一个公共静态类,如下所示:
public class HomeController
{
public static class Buttons
{
public const string Save = "Save";
public const string AddSomething = "Add something";
}
// Action methods
}
所以你可以使用它们来渲染表格:
<input type="submit" name="submit-button" value="@HomeController.Buttons.Save" />
您可以轻松阅读在控制器中点击的按钮:
[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();
}
在Save方法中,首先询问ModelState.IsValid是否返回视图模型,如果没有,但在AddSomething方法中我们将清除任何错误:
public ActionResult AddSomething(Model viewModel)
{
ModelState.Clear();
// your code to add something to model
return View(viewModel);
}
这是你保持一切干净,整洁和可测试。并且您可以为submit-button html name属性引入常量。也许可以用T4MVC做所有常量。类似的解决方案适用于需要“自动回发”组合框的情况,除非您需要通过select元素的onchange事件设置的隐藏字段。
希望这有帮助。
答案 4 :(得分:2)
只需将此代码用作模板:
@{
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"/>
答案 5 :(得分:1)
我要做的最后一件事是使用enum
来确定每个输入标记的值,而不是使用智能字符串。使用剃刀语法:
@Enum.GetName(typeof(YourEnumType), yourEnum.WhateverValue)
然后在你的控制器中:
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();
}
答案 6 :(得分:0)
如果您想要删除单独的操作,请尝试此操作。
在控制器中添加删除操作,并将其标记为HttpDelete
,
[HttpDelete]
public ActionResult Edit(int id, string foo) {
...
}
在视图中,
按钮名称应为X-HTTP-Method-Override
,值应为DELETE
<button name="X-HTTP-Method-Override" value="DELETE" formnovalidate="formnovalidate" class="cancel">Delete</button>
注意: 所有浏览器都不允许使用其他HTTP方法,例如HEAD,PUT或DELETE。但是通过向HTTP请求X-HTTP-Method-Override
添加一个标头,该标头应该被服务解释并且无论使用何种实际的HTTP方法都会对其执行操作。因此,上面的代码会为X-HTTP-Method-Override: DELETE
之类的请求添加标头。和.net框架将执行其余的操作并指示您删除操作。
答案 7 :(得分:0)
提交按钮名称不会来到服务器端,如果完全从这种情况出发,您将使用[Remote]属性作为验证模型属性。