是否有一些简单的方法来处理来自同一个表单的多个提交按钮?例如:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>
知道如何在ASP中做到这一点吗?NET框架测试版?我在谷歌上搜索的所有例子中都有单个按钮。
是否有一些简单的方法来处理来自同一个表单的多个提交按钮?例如:
<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %>
<input type="submit" value="Send" />
<input type="submit" value="Cancel" />
<% Html.EndForm(); %>
知道如何在ASP中做到这一点吗?NET框架测试版?我在谷歌上搜索的所有例子中都有单个按钮。
当前回答
以下是最适合我的方法:
<input type="submit" value="Delete" name="onDelete" />
<input type="submit" value="Save" name="onSave" />
public ActionResult Practice(MyModel model, string onSave, string onDelete)
{
if (onDelete != null)
{
// Delete the object
...
return EmptyResult();
}
// Save the object
...
return EmptyResult();
}
其他回答
这个脚本允许指定一个data-form-action属性,它将在所有浏览器中作为HTML5 formaction属性(以一种不引人注目的方式):
$(document).on('click', '[type="submit"][data-form-action]', function(event) {
var $this = $(this),
var formAction = $this.attr('data-form-action'),
$form = $($this.closest('form'));
$form.attr('action', formAction);
});
包含按钮的表单将被发送到data-form-action属性中指定的URL:
<button type="submit" data-form-action="different/url">Submit</button>
这需要jQuery 1.7。对于以前的版本,您应该使用live()而不是on()。
下面是我写的一个扩展方法来处理多个图像和/或文本按钮。
下面是一个图片按钮的HTML:
<input id="btnJoin" name="Join" src="/content/images/buttons/btnJoin.png"
type="image">
或者对于文本提交按钮:
<input type="submit" class="ui-button green" name="Submit_Join" value="Add to cart" />
<input type="submit" class="ui-button red" name="Submit_Skip" value="Not today" />
下面是使用form.GetSubmitButtonName()从控制器调用的扩展方法。对于图像按钮,它查找带有.x的表单参数(表示单击了图像按钮)并提取名称。对于常规输入按钮,它查找以Submit_开头的名称并从中提取命令。因为我抽象了确定“命令”的逻辑,所以你可以在客户端上切换图像+文本按钮,而无需更改服务器端代码。
public static class FormCollectionExtensions
{
public static string GetSubmitButtonName(this FormCollection formCollection)
{
return GetSubmitButtonName(formCollection, true);
}
public static string GetSubmitButtonName(this FormCollection formCollection, bool throwOnError)
{
var imageButton = formCollection.Keys.OfType<string>().Where(x => x.EndsWith(".x")).SingleOrDefault();
var textButton = formCollection.Keys.OfType<string>().Where(x => x.StartsWith("Submit_")).SingleOrDefault();
if (textButton != null)
{
return textButton.Substring("Submit_".Length);
}
// we got something like AddToCart.x
if (imageButton != null)
{
return imageButton.Substring(0, imageButton.Length - 2);
}
if (throwOnError)
{
throw new ApplicationException("No button found");
}
else
{
return null;
}
}
}
注意:对于文本按钮,必须在名称前加上Submit_。我更喜欢这种方式,因为这意味着您可以更改文本(显示)值,而不必更改代码。与SELECT元素不同,INPUT按钮只有一个“value”,没有单独的“text”属性。我的按钮在不同的上下文中表示不同的内容-但映射到相同的“命令”。我更喜欢以这种方式提取名称,而不是必须为==“Add to cart”编码。
我建议感兴趣的人看看Maarten Balliauw的解决方案。我认为它非常优雅。
如果链接消失,它将使用应用于控制器操作的MultiButton属性来指示该操作应该与哪个按钮单击相关。
刚刚写了一篇相关的文章: 多个提交按钮与ASP。NET MVC:
基本上,我用的不是ActionMethodSelectorAttribute,而是 ActionNameSelectorAttribute,它允许我假装动作名是我想要的任何东西。幸运的是,ActionNameSelectorAttribute不只是让我指定操作名称,而是我可以选择当前操作是否与请求匹配。
这就是我的班级(顺便说一句,我不太喜欢这个名字):
public class HttpParamActionAttribute : ActionNameSelectorAttribute {
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) {
if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase))
return true;
if (!actionName.Equals("Action", StringComparison.InvariantCultureIgnoreCase))
return false;
var request = controllerContext.RequestContext.HttpContext.Request;
return request[methodInfo.Name] != null;
}
}
只需要像这样定义一个表单:
<% using (Html.BeginForm("Action", "Post")) { %>
<!— …form fields… -->
<input type="submit" name="saveDraft" value="Save Draft" />
<input type="submit" name="publish" value="Publish" />
<% } %>
控制器有两个方法
public class PostController : Controller {
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveDraft(…) {
//…
}
[HttpParamAction]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Publish(…) {
//…
}
}
如您所见,该属性根本不需要指定任何内容。此外,按钮的名称直接转换为方法名称。此外(我还没有尝试过)这些应该作为正常的动作以及,所以你可以张贴到他们中的任何一个 直接。
这是我发现的最好的方法:
http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html
代码如下:
/// <summary>
/// ActionMethodSelector to enable submit buttons to execute specific action methods.
/// </summary>
public class AcceptParameterAttribute : ActionMethodSelectorAttribute
{
/// <summary>
/// Gets or sets the value to use to inject the index into
/// </summary>
public string TargetArgument { get; set; }
/// <summary>
/// Gets or sets the value to use in submit button to identify which method to select. This must be unique in each controller.
/// </summary>
public string Action { get; set; }
/// <summary>
/// Gets or sets the regular expression to match the action.
/// </summary>
public string ActionRegex { get; set; }
/// <summary>
/// Determines whether the action method selection is valid for the specified controller context.
/// </summary>
/// <param name="controllerContext">The controller context.</param>
/// <param name="methodInfo">Information about the action method.</param>
/// <returns>true if the action method selection is valid for the specified controller context; otherwise, false.</returns>
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
Func<NameValueCollection> formGetter;
Func<NameValueCollection> queryStringGetter;
ValidationUtility.GetUnvalidatedCollections(HttpContext.Current, out formGetter, out queryStringGetter);
var form = formGetter();
var queryString = queryStringGetter();
var req = form.AllKeys.Any() ? form : queryString;
if (!string.IsNullOrEmpty(this.ActionRegex))
{
foreach (var key in req.AllKeys.Where(k => k.StartsWith(Action, true, System.Threading.Thread.CurrentThread.CurrentCulture)))
{
if (key.Contains(":"))
{
if (key.Split(':').Count() == this.ActionRegex.Split(':').Count())
{
bool match = false;
for (int i = 0; i < key.Split(':').Count(); i++)
{
if (Regex.IsMatch(key.Split(':')[0], this.ActionRegex.Split(':')[0]))
{
match = true;
}
else
{
match = false;
break;
}
}
if (match)
{
return !string.IsNullOrEmpty(req[key]);
}
}
}
else
{
if (Regex.IsMatch(key, this.Action + this.ActionRegex))
{
return !string.IsNullOrEmpty(req[key]);
}
}
}
return false;
}
else
{
return req.AllKeys.Contains(this.Action);
}
}
}
享受一个没有代码气味的多提交按钮的未来。
谢谢你!