tutorial net mvc botones asp html asp.net asp.net-mvc http-post form-submit

html - botones - asp.net web forms vs mvc



¿Cómo maneja los múltiples botones de envío en ASP.NET MVC Framework? (30)

Acaba de escribir una publicación sobre eso: Múltiples botones de envío con ASP.NET MVC :

Básicamente, en lugar de usar ActionMethodSelectorAttribute , estoy usando ActionNameSelectorAttribute , que me permite fingir que el nombre de la acción es lo que quiero que sea. Afortunadamente, ActionNameSelectorAttribute no solo me hace especificar el nombre de la acción, sino que puedo elegir si la acción actual coincide con la solicitud.

Así que ahí está mi clase (por cierto no me gusta mucho el nombre):

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; } }

Para usar solo define un formulario como este:

<% using (Html.BeginForm("Action", "Post")) { %> <!— …form fields… --> <input type="submit" name="saveDraft" value="Save Draft" /> <input type="submit" name="publish" value="Publish" /> <% } %>

y controlador con dos métodos.

public class PostController : Controller { [HttpParamAction] [AcceptVerbs(HttpVerbs.Post)] public ActionResult SaveDraft(…) { //… } [HttpParamAction] [AcceptVerbs(HttpVerbs.Post)] public ActionResult Publish(…) { //… } }

Como ve, el atributo no requiere que especifique nada en absoluto. Además, el nombre de los botones se traduce directamente a los nombres de los métodos. Además (no lo he intentado), también deberían funcionar como acciones normales, por lo que puede publicar en cualquiera de ellas directamente.

¿Hay alguna manera fácil de manejar múltiples botones de envío desde el mismo formulario? Ejemplo:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %> <input type="submit" value="Send" /> <input type="submit" value="Cancel" /> <% Html.EndForm(); %>

¿Alguna idea de cómo hacer esto en ASP.NET Framework Beta? Todos los ejemplos que he buscado en Google tienen botones individuales en ellos.


Algo que no me gusta de ActionSelectName es que se llama a IsValidName para cada método de acción en el controlador; No sé por qué funciona de esta manera. Me gusta una solución donde cada botón tiene un nombre diferente según lo que hace, pero no me gusta el hecho de que tenga que tener tantos parámetros en el método de acción como botones en el formulario. He creado una enumeración para todos los tipos de botones:

public enum ButtonType { Submit, Cancel, Delete }

En lugar de ActionSelectName, uso un ActionFilter:

public class MultipleButtonsEnumAttribute : ActionFilterAttribute { public Type EnumType { get; set; } public MultipleButtonsEnumAttribute(Type enumType) { EnumType = enumType; } public override void OnActionExecuting(ActionExecutingContext filterContext) { foreach (var key in filterContext.HttpContext.Request.Form.AllKeys) { if (Enum.IsDefined(EnumType, key)) { var pDesc = filterContext.ActionDescriptor.GetParameters() .FirstOrDefault(x => x.ParameterType == EnumType); filterContext.ActionParameters[pDesc.ParameterName] = Enum.Parse(EnumType, key); break; } } } }

El filtro encontrará el nombre del botón en los datos del formulario y, si el nombre del botón coincide con alguno de los tipos de botones definidos en la enumeración, encontrará el parámetro ButtonType entre los parámetros de acción:

[MultipleButtonsEnumAttribute(typeof(ButtonType))] public ActionResult Manage(ButtonType buttonPressed, ManageViewModel model) { if (button == ButtonType.Cancel) { return RedirectToAction("Index", "Home"); } //and so on return View(model) }

y luego en vistas, puedo usar:

<input type="submit" value="Button Cancel" name="@ButtonType.Cancel" /> <input type="submit" value="Button Submit" name="@ButtonType.Submit" />


Aquí hay un método de extensión que escribí para manejar varios botones de imagen y / o texto.

Aquí está el HTML para un botón de imagen:

<input id="btnJoin" name="Join" src="/content/images/buttons/btnJoin.png" type="image">

o para un botón de envío de texto:

<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" />

Aquí está el método de extensión al que llama desde el controlador con form.GetSubmitButtonName() . Para los botones de imagen busca un parámetro de formulario con .x (que indica que se hizo clic en un botón de imagen) y extrae el nombre. Para input botones de input regulares, busca un nombre que comience con Submit_ y luego extrae el comando. Debido a que estoy abstrayendo la lógica de determinar el ''comando'', puede cambiar entre los botones de imagen + texto en el cliente sin cambiar el código del lado del servidor.

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; } } }

Nota: Para los botones de texto, debe prefijar el nombre con Submit_ . Prefiero esta manera porque significa que puede cambiar el valor del texto (pantalla) sin tener que cambiar el código. A diferencia de los elementos SELECT , un botón de INPUT tiene solo un atributo de ''valor'' y no un ''texto'' separado. Mis botones dicen cosas diferentes en contextos diferentes, pero se asignan al mismo ''comando''. Prefiero extraer el nombre de esta manera que tener que codificar para == "Add to cart" .


Aquí hay una solución basada principalmente en atributos limpios para el problema del botón de envío múltiple basado en gran medida en la publicación y los comentarios de Maartin Balliauw .

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class MultipleButtonAttribute : ActionNameSelectorAttribute { public string Name { get; set; } public string Argument { get; set; } public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { var isValidName = false; var keyValue = string.Format("{0}:{1}", Name, Argument); var value = controllerContext.Controller.ValueProvider.GetValue(keyValue); if (value != null) { controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument; isValidName = true; } return isValidName; } }

maquinilla de afeitar:

<form action="" method="post"> <input type="submit" value="Save" name="action:Save" /> <input type="submit" value="Cancel" name="action:Cancel" /> </form>

y controlador:

[HttpPost] [MultipleButton(Name = "action", Argument = "Save")] public ActionResult Save(MessageModel mm) { ... } [HttpPost] [MultipleButton(Name = "action", Argument = "Cancel")] public ActionResult Cancel(MessageModel mm) { ... }

Actualización: las páginas de Razor parecen proporcionar la misma funcionalidad de forma inmediata. Para nuevos desarrollos, puede ser preferible.


Asígnele un nombre a sus botones de envío y luego inspeccione el valor enviado en su método de control:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %> <input type="submit" name="submitButton" value="Send" /> <input type="submit" name="submitButton" value="Cancel" /> <% Html.EndForm(); %>

publicar en

public class MyController : Controller { public ActionResult MyAction(string submitButton) { switch(submitButton) { case "Send": // delegate sending to another controller action return(Send()); case "Cancel": // call another action to perform the cancellation return(Cancel()); default: // If they''ve submitted the form without a submitButton, // just return the view again. return(View()); } } private ActionResult Cancel() { // process the cancellation request here. return(View("Cancelled")); } private ActionResult Send() { // perform the actual send operation here. return(View("SendConfirmed")); } }

EDITAR:

Para ampliar este enfoque para trabajar con sitios localizados, aísle sus mensajes en otro lugar (por ejemplo, compilando un archivo de recursos en una clase de recursos fuertemente tipada)

Luego modifica el código para que funcione como:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %> <input type="submit" name="submitButton" value="<%= Html.Encode(Resources.Messages.Send)%>" /> <input type="submit" name="submitButton" value="<%=Html.Encode(Resources.Messages.Cancel)%>" /> <% Html.EndForm(); %>

y su controlador debe tener este aspecto:

// Note that the localized resources aren''t constants, so // we can''t use a switch statement. if (submitButton == Resources.Messages.Send) { // delegate sending to another controller action return(Send()); } else if (submitButton == Resources.Messages.Cancel) { // call another action to perform the cancellation return(Cancel()); }


David Findley escribe sobre 3 opciones diferentes que tiene para hacer esto, en su weblog ASP.Net.

Lea los múltiples botones del artículo en la misma forma para ver sus soluciones, y las ventajas y desventajas de cada uno. En mi humilde opinión, proporciona una solución muy elegante que utiliza atributos con los que decoras tu acción.


Debes poder nombrar los botones y darles un valor; luego mapee este nombre como un argumento a la acción. Alternativamente, use 2 enlaces de acción separados o 2 formularios.


Eilon sugiere que puedes hacerlo así:

Si tiene más de un botón, puede distinguirlos al asignar un nombre a cada botón:

<input type="submit" name="SaveButton" value="Save data" /> <input type="submit" name="CancelButton" value="Cancel and go back to main page" />

En su método de acción del controlador puede agregar parámetros nombrados después de los nombres de las etiquetas de entrada HTML:

public ActionResult DoSomeStuff(string saveButton, string cancelButton, ... other parameters ...) { ... }

Si algún valor se publica en uno de esos parámetros, eso significa que ese botón fue el que se hizo clic. El navegador web solo publicará un valor para el botón que se hizo clic. Todos los demás valores serán nulos.

if (saveButton != null) { /* do save logic */ } if (cancelButton != null) { /* do cancel logic */ }

Me gusta este método, ya que no se basa en la propiedad de valor de los botones de envío, que es más probable que cambie que los nombres asignados y que no requiera la activación de JavaScript.

Consulte: http://forums.asp.net/p/1369617/2865166.aspx#2865166


Es corto y suite.

Fue contestado por Jeroen Dop.

<input type="submit" name="submitbutton1" value="submit1" /> <input type="submit" name="submitbutton2" value="submit2" />

y haz así en código behinde

if( Request.Form["submitbutton1"] != null) { // Code for function 1 } else if(Request.Form["submitButton2"] != null ) { // code for function 2 }

Buena suerte.


Esta es la técnica que usaría y no la veo aquí todavía. El enlace (publicado por Saajid Ismail) que inspira esta solución es http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form .aspx ). Adapta la respuesta de Dylan Beattie para realizar la localización sin problemas.

En la vista:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %> <button name="button" value="send"><%: Resources.Messages.Send %></button> <button name="button" value="cancel"><%: Resources.Messages.Cancel %></button> <% Html.EndForm(); %>

En el controlador:

public class MyController : Controller { public ActionResult MyAction(string button) { switch(button) { case "send": this.DoSend(); break; case "cancel": this.DoCancel(); break; } } }


Este script permite especificar un atributo de acción de formulario de datos que funcionará como el atributo de forma HTML5 en todos los navegadores (de manera discreta):

$(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); });

El formulario que contiene el botón se publicará en la URL especificada en el atributo data-form-action:

<button type="submit" data-form-action="different/url">Submit</button>

Esto requiere jQuery 1.7. Para versiones anteriores, debe usar live() lugar de on() .


Esto es lo que funciona mejor para mí:

<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(); }


Hay tres formas en que puede resolver el problema anterior

  1. Forma HTML
  2. Forma jquery
  3. "ActionNameSelectorAttribute" forma

A continuación se muestra un video que resume los tres enfoques de manera demostrativa.

https://www.facebook.com/shivprasad.koirala/videos/vb.100002224977742/809335512483940

Forma HTML: -

En la forma HTML, necesitamos crear dos formularios y colocar el botón "Enviar" dentro de cada uno de los formularios. Y la acción de cada forma apuntará a acciones diferentes / respectivas. Puede ver el siguiente código: el primer formulario se publica en "Action1" y el segundo se publicará en "Action2" según el botón "Enviar".

<form action="Action1" method=post> <input type=”submit” name=”Submit1”/> </form> <form action="Action2" method=post> <input type=”submit” name=”Submit2”> </form>

Ajax forma: -

En caso de que seas un amante del Ajax, esta segunda opción te excitará más. A la manera de Ajax podemos crear dos funciones diferentes "Fun1" y "Fun1", consulte el siguiente código. Estas funciones realizarán llamadas a Ajax utilizando JQUERY o cualquier otro framework. Cada una de estas funciones se enlaza con los eventos "OnClick" del botón "Enviar". Cada una de estas funciones llama a los respectivos nombres de acción.

<Script language="javascript"> function Fun1() { $.post(“/Action1”,null,CallBack1); } function Fun2() { $.post(“/Action2”,null,CallBack2); } </Script> <form action="/Action1" method=post> <input type=submit name=sub1 onclick=”Fun2()”/> </form> <form action="/Action2" method=post> <input type=submit name=sub2 onclick=”Fun1()”/> </form>

Utilizando "ActionNameSelectorAttribute": -

Esta es una gran y una opción limpia. El "ActionNameSelectorAttribute" es una clase de atributo simple donde podemos escribir la lógica de toma de decisiones que decidirá qué acción se puede ejecutar.

Entonces, lo primero que hay en HTML es que debemos poner un nombre adecuado en los botones de envío para identificarlos en el servidor.

Puede ver que hemos puesto "Guardar" y "Eliminar" en los nombres de los botones. También puede observar en la acción que acabamos de poner el nombre del controlador "Cliente" y no un nombre de acción en particular. Esperamos que el nombre de la acción se decida por "ActionNameSelectorAttribute".

<form action=”Customer” method=post> <input type=submit value="Save" name="Save" /> <br /> <input type=submit value="Delete" name="Delete"/> </form>

Entonces, cuando se hace clic en el botón de envío, primero golpea el atributo "ActionNameSelector" y luego, dependiendo de qué envío se activa, se invoca la acción apropiada.

Entonces, el primer paso es crear una clase que herede de la clase "ActionNameSelectorAttribute". En esta clase hemos creado una propiedad simple "Nombre".

También debemos anular la función "IsValidName" que devuelve true o flase. Esta función es donde escribimos la lógica si una acción tiene que ser ejecutada o no. Entonces, si esta función devuelve verdadero, entonces la acción se ejecuta o no lo es.

public class SubmitButtonSelector : ActionNameSelectorAttribute { public string Name { get; set; } public override bool IsValidName(ControllerContext controllerContext, string actionName, System.Reflection.MethodInfo methodInfo) { // Try to find out if the name exists in the data sent from form var value = controllerContext.Controller.ValueProvider.GetValue(Name); if (value != null) { return true; } return false; } }

El corazón principal de la función anterior se encuentra en el siguiente código. La colección "ValueProvider" tiene todos los datos que se han publicado desde el formulario. Por lo tanto, primero busca el valor de "Nombre" y, si se encuentra en la solicitud HTTP, devuelve verdadero o, si no, devuelve falso.

var value = controllerContext.Controller.ValueProvider.GetValue(Name); if (value != null) { return true; } return false;

Esta clase de atributo puede decorarse en la acción respectiva y se puede proporcionar el valor de "Nombre" respectivo. Por lo tanto, si el envío está realizando esta acción y si el nombre coincide con el nombre del botón de envío HTML, se ejecutará la acción o no.

public class CustomerController : Controller { [SubmitButtonSelector(Name="Save")] public ActionResult Save() { return Content("Save Called"); } [SubmitButtonSelector(Name = "Delete")] public ActionResult Delete() { return Content("Delete Called"); } }


He intentado hacer una síntesis de todas las soluciones y he creado un atributo [ButtenHandler] que facilita el manejo de múltiples botones en un formulario.

Lo he descrito en CodeProject Múltiples botones de formulario parametrizados (localizables) en ASP.NET MVC .

Para manejar el caso simple de este botón:

<button type="submit" name="AddDepartment">Add Department</button>

Tendrás algo como el siguiente método de acción:

[ButtonHandler()] public ActionResult AddDepartment(Company model) { model.Departments.Add(new Department()); return View(model); }

Observe cómo el nombre del botón coincide con el nombre del método de acción. El artículo también describe cómo tener botones con valores y botones con índices.


No tengo suficiente representante para comentar en el lugar correcto, pero me pasé todo el día en esto, así que quiero compartir.

Al intentar implementar la solución "MultipleButtonAttribute", ValueProvider.GetValue(keyValue) volvería incorrectamente a null .

Resultó que estaba haciendo referencia a System.Web.MVC versión 3.0 cuando debería haber sido 4.0 (otros ensamblajes son 4.0). No sé por qué mi proyecto no se actualizó correctamente y no tuve otros problemas obvios.

Entonces, si su ActionNameSelectorAttribute no está funcionando ... verifique eso.


Podrías escribir:

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %> <input type="submit" name="button" value="Send" /> <input type="submit" name="button" value="Cancel" /> <% Html.EndForm(); %>

Y luego, en la página, compruebe si el nombre == "Enviar" o el nombre == "Cancelar" ...


Puede verificar el nombre en la acción como se ha mencionado, pero puede considerar si este es un buen diseño o no. Es una buena idea considerar la responsabilidad de la acción y no acoplar demasiado este diseño a los aspectos de la interfaz de usuario, como los nombres de los botones. Así que considera usar 2 formas y 2 acciones:

<% Html.BeginForm("Send", "MyController", FormMethod.Post); %> <input type="submit" name="button" value="Send" /> <% Html.EndForm(); %> <% Html.BeginForm("Cancel", "MyController", FormMethod.Post); %> <input type="submit" name="button" value="Cancel" /> <% Html.EndForm(); %>

Además, en el caso de "Cancelar", normalmente no está procesando el formulario y va a una nueva URL. En este caso, no necesita enviar el formulario y solo necesita un enlace:

<%=Html.ActionLink("Cancel", "List", "MyController") %>


Si no tiene restricciones en el uso de HTML 5, puede usar la etiqueta <button> con el atributo de formaction :

<form action="demo_form.asp" method="get"> First name: <input type="text" name="fname" /><br /> Last name: <input type="text" name="lname" /><br /> <button type="submit">Submit</button><br /> <button type="submit" formaction="demo_admin.asp">Submit as admin</button> </form>

Referencia: http://www.w3schools.com/html5/att_button_formaction.asp


Si su navegador admite la formación de atributos para los botones de entrada (IE 10+, no está seguro acerca de otros navegadores), lo siguiente debería funcionar:

@using (Html.BeginForm()){ //put form inputs here <input id="sendBtn" value="Send" type="submit" formaction="@Url.Action("Name Of Send Action")" /> <input id="cancelBtn" value="Cancel" type="submit" formaction="@Url.Action("Name of Cancel Action") /> }


Sugeriría a las partes interesadas echar un vistazo a la solución de Maarten Balliauw . Creo que es muy elegante.

En caso de que el enlace desaparezca, está utilizando el atributo MultiButton aplicado a una acción del controlador para indicar qué botón debe hacer clic en esa acción.


También encontré este ''problema'' pero encontré una solución bastante lógica al agregar el atributo de name . No recuerdo haber tenido este problema en otros idiomas.

http://www.w3.org/TR/html401/interact/forms.html#h-17.13.2

  • ...
  • Si un formulario contiene más de un botón de envío, solo el botón de envío activado tendrá éxito.
  • ...

Lo que significa que los siguientes atributos de value código se pueden cambiar, localizar, internacionalizar sin la necesidad de código adicional que compruebe los archivos o constantes de recursos fuertemente tipados.

<% Html.BeginForm("MyAction", "MyController", FormMethod.Post); %> <input type="submit" name="send" value="Send" /> <input type="submit" name="cancel" value="Cancel" /> <input type="submit" name="draft" value="Save as draft" /> <% Html.EndForm(); %>`

En el lado de recepción, solo tendría que comprobar si alguno de sus tipos de envío conocidos no es null

public ActionResult YourAction(YourModel model) { if(Request["send"] != null) { // we got a send }else if(Request["cancel"]) { // we got a cancel, but would you really want to post data for this? }else if(Request["draft"]) { // we got a draft } }


Esta es la mejor manera que he encontrado:

http://iwayneo.blogspot.co.uk/2013/10/aspnet-mvc-action-selector-with-list.html

Aquí está el código:

/// <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); } } }

Disfrute de un futuro botón de envío múltiple sin olor de código.

gracias


Mi enfoque JQuery utilizando un método de extensión:

public static MvcHtmlString SubmitButtonFor<TController>(this HtmlHelper helper, Expression<Action<TController>> action, string value) where TController : Controller { RouteValueDictionary routingValues = Microsoft.Web.Mvc.Internal.ExpressionHelper.GetRouteValuesFromExpression(action); var onclick = string.Format("$(''form'').first().attr(''action'', ''/{0}'')", string.Join("/", routingValues.Values.ToArray().Where(x => x != null).Select(x => x.ToString()).ToArray())); var html = "<input type=/"submit/" value=/"" + value + "/" onclick=/"" + onclick + "/" />"; return MvcHtmlString.Create(html); }

Puedes usarlo así:

@(Html.SubmitButtonFor<FooController>(c => c.Save(null), "Save"))

Y se hace así:

<input type="submit" value="Save" onclick="$(''form'').first().attr(''action'', ''/Foo/Save'')" >


Para cada botón de envío simplemente agregue:

$(''#btnSelector'').click(function () { $(''form'').attr(''action'', "/Your/Action/); $(''form'').submit(); });


Basado en la respuesta de mkozicki, se me ocurre una solución un poco diferente. Todavía utilizo ActionNameSelectorAttributePero necesitaba manejar dos botones ''Guardar'' y ''Sincronizar''. Hacen casi lo mismo, así que no quería tener dos acciones.

atributo :

public class MultipleButtonActionAttribute : ActionNameSelectorAttribute { private readonly List<string> AcceptedButtonNames; public MultipleButtonActionAttribute(params string[] acceptedButtonNames) { AcceptedButtonNames = acceptedButtonNames.ToList(); } public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { foreach (var acceptedButtonName in AcceptedButtonNames) { var button = controllerContext.Controller.ValueProvider.GetValue(acceptedButtonName); if (button == null) { continue; } controllerContext.Controller.ControllerContext.RouteData.Values.Add("ButtonName", acceptedButtonName); return true; } return false; } }

ver

<input type="submit" value="Save" name="Save" /> <input type="submit" value="Save and Sync" name="Sync" />

controlador

[MultipleButtonAction("Save", "Sync")] public ActionResult Sync(OrgSynchronizationEditModel model) { var btn = this.RouteData.Values["ButtonName"];

También quiero señalar que si las acciones hacen cosas diferentes, probablemente seguiría la publicación de mkozicki.


He creado un método ActionButton para el HtmlHelper . Generará un botón de entrada normal con un poco de javascript en el evento OnClick que enviará el formulario al Controlador / Acción especificado.

Usas el ayudante asi

@Html.ActionButton("MyControllerName", "MyActionName", "button text")

esto generará el siguiente HTML

<input type="button" value="button text" onclick="this.form.action = ''/MyWebsiteFolder/MyControllerName/MyActionName''; this.form.submit();">

Aquí está el código del método de extensión:

VB.Net

<System.Runtime.CompilerServices.Extension()> Function ActionButton(pHtml As HtmlHelper, pAction As String, pController As String, pRouteValues As Object, pBtnValue As String, pBtnName As String, pBtnID As String) As MvcHtmlString Dim urlHelperForActionLink As UrlHelper Dim btnTagBuilder As TagBuilder Dim actionLink As String Dim onClickEventJavascript As String urlHelperForActionLink = New UrlHelper(pHtml.ViewContext.RequestContext) If pController <> "" Then actionLink = urlHelperForActionLink.Action(pAction, pController, pRouteValues) Else actionLink = urlHelperForActionLink.Action(pAction, pRouteValues) End If onClickEventJavascript = "this.form.action = ''" & actionLink & "''; this.form.submit();" btnTagBuilder = New TagBuilder("input") btnTagBuilder.MergeAttribute("type", "button") btnTagBuilder.MergeAttribute("onClick", onClickEventJavascript) If pBtnValue <> "" Then btnTagBuilder.MergeAttribute("value", pBtnValue) If pBtnName <> "" Then btnTagBuilder.MergeAttribute("name", pBtnName) If pBtnID <> "" Then btnTagBuilder.MergeAttribute("id", pBtnID) Return MvcHtmlString.Create(btnTagBuilder.ToString(TagRenderMode.Normal)) End Function

C # (el código C # solo se ha descompilado de la DLL de VB, por lo que se puede embellecer ... pero el tiempo es muy corto :-)

public static MvcHtmlString ActionButton(this HtmlHelper pHtml, string pAction, string pController, object pRouteValues, string pBtnValue, string pBtnName, string pBtnID) { UrlHelper urlHelperForActionLink = new UrlHelper(pHtml.ViewContext.RequestContext); bool flag = Operators.CompareString(pController, "", true) != 0; string actionLink; if (flag) { actionLink = urlHelperForActionLink.Action(pAction, pController, System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(pRouteValues)); } else { actionLink = urlHelperForActionLink.Action(pAction, System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(pRouteValues)); } string onClickEventJavascript = "this.form.action = ''" + actionLink + "''; this.form.submit();"; TagBuilder btnTagBuilder = new TagBuilder("input"); btnTagBuilder.MergeAttribute("type", "button"); btnTagBuilder.MergeAttribute("onClick", onClickEventJavascript); flag = (Operators.CompareString(pBtnValue, "", true) != 0); if (flag) { btnTagBuilder.MergeAttribute("value", pBtnValue); } flag = (Operators.CompareString(pBtnName, "", true) != 0); if (flag) { btnTagBuilder.MergeAttribute("name", pBtnName); } flag = (Operators.CompareString(pBtnID, "", true) != 0); if (flag) { btnTagBuilder.MergeAttribute("id", pBtnID); } return MvcHtmlString.Create(btnTagBuilder.ToString(TagRenderMode.Normal)); }

Estos métodos tienen varios parámetros, pero para la facilidad de uso, puede crear una sobrecarga que tome solo los parámetros que necesita.


Llego tarde a la fiesta, pero aquí va ... Mi implementación toma prestada de @mkozicki pero requiere menos cadenas codificadas para equivocarse. Marco 4.5+ requerido . Esencialmente, el nombre del método del controlador debe ser la clave para el enrutamiento.

De marcado . El nombre del botón debe estar escrito con"action:[controllerMethodName]"

(observe el uso del nameof API de C # 6 , que proporciona una referencia específica del tipo al nombre del método del controlador que desea invocar).

<form> ... form fields .... <button name="action:@nameof(MyApp.Controllers.MyController.FundDeathStar)" type="submit" formmethod="post">Fund Death Star</button> <button name="action:@nameof(MyApp.Controllers.MyController.HireBoba)" type="submit" formmethod="post">Hire Boba Fett</button> </form>

Controlador :

namespace MyApp.Controllers { class MyController { [SubmitActionToThisMethod] public async Task<ActionResult> FundDeathStar(ImperialModel model) { await TrainStormTroopers(); return View(); } [SubmitActionToThisMethod] public async Task<ActionResult> HireBoba(ImperialModel model) { await RepairSlave1(); return View(); } } }

Atributo de la magia . Note el uso de la CallerMemberNamebondad.

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class SubmitActionToThisMethodAttribute : ActionNameSelectorAttribute { public SubmitActionToThisMethodAttribute([CallerMemberName]string ControllerMethodName = "") { controllerMethod = ControllerMethodName; actionFormat = string.Concat(actionConstant, ":", controllerMethod); } const string actionConstant = "action"; readonly string actionFormat; readonly string controllerMethod; public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { var isValidName = false; var value = controllerContext.Controller.ValueProvider.GetValue(actionFormat); if (value != null) { controllerContext.Controller.ControllerContext.RouteData.Values[actionConstant] = controllerMethod; isValidName = true; } return isValidName; } }


Versión modificada del HttpParamActionAttributemétodo pero con una solución de error para no causar un error en las devoluciones de datos de sesión caducadas / inválidas. Para ver si este es un problema con su sitio actual, abra el formulario en una ventana y justo antes de hacer clic Saveo Publishabra una ventana duplicada y cierre la sesión. Ahora regrese a su primera ventana e intente enviar su formulario usando cualquiera de los botones. Para mí, recibí un error, por lo que este cambio resuelve ese problema para mí. Omito un montón de cosas por razones de brevedad, pero deberías tener la idea. Las partes clave son la inclusión de ActionNameen el atributo y asegurarse de que el nombre pasado sea el nombre de la Vista que muestra el formulario

Clase de atributo

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class HttpParamActionAttribute : ActionNameSelectorAttribute { private readonly string actionName; public HttpParamActionAttribute(string actionName) { this.actionName = actionName; } public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { if (actionName.Equals(methodInfo.Name, StringComparison.InvariantCultureIgnoreCase)) return true; if (!actionName.Equals(this.actionName, StringComparison.InvariantCultureIgnoreCase)) return false; var request = controllerContext.RequestContext.HttpContext.Request; return request[methodInfo.Name] != null; } }

Controlador

[Authorize(Roles="CanAddContent")] public ActionResult CreateContent(Guid contentOwnerId) { var viewModel = new ContentViewModel { ContentOwnerId = contentOwnerId //populate rest of view model } return View("CreateContent", viewModel); } [Authorize(Roles="CanAddContent"), HttpPost, HttpParamAction("CreateContent"), ValidateAntiForgeryToken] public ActionResult SaveDraft(ContentFormModel model) { //Save as draft return RedirectToAction("CreateContent"); } [Authorize(Roles="CanAddContent"), HttpPost, HttpParamAction("CreateContent"), ValidateAntiForgeryToken] public ActionResult Publish(ContentFormModel model) { //publish content return RedirectToAction("CreateContent"); }

Ver

@using (Ajax.BeginForm("CreateContent", "MyController", new { contentOwnerId = Model.ContentOwnerId })) { @Html.AntiForgeryToken() @Html.HiddenFor(x => x.ContentOwnerId) <!-- Rest of your form controls --> <input name="SaveDraft" type="submit" value="SaveDraft" /> <input name="Publish" type="submit" value="Publish" /> }


//model public class input_element { public string Btn { get; set; } } //views--submit btn can be input type also... @using (Html.BeginForm()) { <button type="submit" name="btn" value="verify"> Verify data</button> <button type="submit" name="btn" value="save"> Save data</button> <button type="submit" name="btn" value="redirect"> Redirect</button> } //controller public ActionResult About() { ViewBag.Message = "Your app description page."; return View(); } [HttpPost] public ActionResult About(input_element model) { if (model.Btn == "verify") { // the Verify button was clicked } else if (model.Btn == "save") { // the Save button was clicked } else if (model.Btn == "redirect") { // the Redirect button was clicked } return View(); }


[HttpPost] public ActionResult ConfirmMobile(string nameValueResend, string nameValueSubmit, RegisterModel model) { var button = nameValueResend ?? nameValueSubmit; if (button == "Resend") { } else { } } Razor file Content: @using (Html.BeginForm() { <div class="page registration-result-page"> <div class="page-title"> <h1> Confirm Mobile Number</h1> </div> <div class="result"> @Html.EditorFor(model => model.VefificationCode) @Html.LabelFor(model => model.VefificationCode, new { }) @Html.ValidationMessageFor(model => model.VefificationCode) </div> <div class="buttons"> <button type="submit" class="btn" name="nameValueResend" value="Resend"> Resend </button> <button type="submit" class="btn" name="nameValueSubmit" value="Verify"> Submit </button> </div> </div> }