MVC que se ha presionado el botón enviar

128

Tengo dos botones en mi formulario MVC:

<input name="submit" type="submit" id="submit" value="Save" />
<input name="process" type="submit" id="process" value="Process" />

Desde mi acción Controlador, ¿cómo sé cuál ha sido presionado?

Coppermill
fuente
¿Por qué no simplemente agregar eventos onclick a estos botones que van a su propia llamada AJAX que irá a sus métodos apropiados? es decir <input name="submit" type="submit" id="submit" value="Save" onclick="saveMethod" />:?
Ragerory

Respuestas:

169

Nombra ambos botones de envío de la misma manera

<input name="submit" type="submit" id="submit" value="Save" />
<input name="submit" type="submit" id="process" value="Process" />

Luego, en su controlador, obtenga el valor de envío. Solo el botón que se haga clic pasará su valor.

public ActionResult Index(string submit)
{
    Response.Write(submit);
    return View();
}

Por supuesto, puede evaluar ese valor para realizar diferentes operaciones con un bloque de interruptores.

public ActionResult Index(string submit)
{
    switch (submit)
    {
        case "Save":
            // Do something
            break;
        case "Process":
            // Do something
            break;
        default:
            throw new Exception();
            break;
    }

    return View();
}
WDuffy
fuente
13
Tenga cuidado con los problemas que la localización podría traer a esta solución, a los que la solución de Darin no es susceptible.
Richard Szalay
Dos entradas con el mismo nombre dan como resultado que se publique una matriz con un elemento para cada valor, no un solo valor implícito. Así que desearía poder decir lo contrario ya que esperaba / intento usar esto, pero esto no funciona.
Christopher King
1
@RichardSzalay: ¿no podría usarlo solo <button type="submit" name="action" value="draft"> Internationalized Save Text </button>para fines de i18n, por lo que el usuario que enfrenta la cadena es personalizable y los nombres de los elementos de formulario nunca se exponen directamente al usuario (lo cual es extraño en sí mismo)
KyleMit
48
<input name="submit" type="submit" id="submit" value="Save" />
<input name="process" type="submit" id="process" value="Process" />

Y en su acción de controlador:

public ActionResult SomeAction(string submit)
{
    if (!string.IsNullOrEmpty(submit))
    {
        // Save was pressed
    }
    else
    {
        // Process was pressed
    }
}
Darin Dimitrov
fuente
1
Me imagino que se podrían agregar más botones simplemente agregándolo a la lista de parámetros y nombrándolo correctamente. Buena solución!
GONeale
35

esta es una mejor respuesta, por lo que podemos tener tanto texto como valor para un botón:

http://weblogs.asp.net/dfindley/archive/2009/05/31/asp-net-mvc-multiple-buttons-in-the-same-form.aspx

</p>
<button name="button" value="register">Register</button>
<button name="button" value="cancel">Cancel</button>
</p>

y el controlador:

public ActionResult Register(string button, string userName, string email, string password, string confirmPassword)
{
if (button == "cancel")
    return RedirectToAction("Index", "Home");
...

en resumen, es un botón ENVIAR, pero usted elige el nombre usando el atributo de nombre, es aún más poderoso porque no está obligado a enviar el nombre o al botón en los parámetros del método del controlador, puede llamarlo como lo desee ...

Mansión Yakir
fuente
Gracias señor, esto es exactamente lo que necesito
oHoodie
Esto se rompe si tiene un sistema multilingüe que cambia el valor del botón según el idioma.
Dave Tapson el
Dave: no creo que nadie codifique un sistema así. Eso es como localizar los nombres de los controladores o los nombres de las funciones. El valor del botón es solo para uso del lado del servidor: no se muestra en ningún lado y no necesita ser localizado.
NickG
20

Puede identificar su botón desde allí la etiqueta de nombre como a continuación, debe marcar así en su controlador

if (Request.Form["submit"] != null)
{
//Write your code here
}
else if (Request.Form["process"] != null)
{
//Write your code here
}
Kinjal Gohil
fuente
Esto es muy útil en situaciones en las que no desea pasar el nombre del botón al resultado de la acción posterior.
yogihosting
En este escenario, puede ser más complicado burlarse de la clase Request en la prueba unitaria.
Muflix
6

Aquí hay una manera muy agradable y sencilla de hacerlo con instrucciones realmente fáciles de seguir utilizando un MultiButtonAttribute personalizado:

http://blog.maartenballiauw.be/post/2009/11/26/Supporting-multiple-submit-buttons-on-an-ASPNET-MVC-view.aspx

Para resumir, haga que sus botones de envío sean así:

<input type="submit" value="Cancel" name="action" />
<input type="submit" value="Create" name="action" /> 

Tus acciones como esta:

[HttpPost]
[MultiButton(MatchFormKey="action", MatchFormValue="Cancel")]
public ActionResult Cancel()
{
    return Content("Cancel clicked");
}

[HttpPost]
[MultiButton(MatchFormKey = "action", MatchFormValue = "Create")]
public ActionResult Create(Person person)
{
    return Content("Create clicked");
} 

Y crea esta clase:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class MultiButtonAttribute : ActionNameSelectorAttribute
{
    public string MatchFormKey { get; set; }
    public string MatchFormValue { get; set; }

    public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
    {
        return controllerContext.HttpContext.Request[MatchFormKey] != null &&
            controllerContext.HttpContext.Request[MatchFormKey] == MatchFormValue;
    }
}
Owen
fuente
1
Siempre es mejor resumir un enlace referenciado (para el día en que el blog desaparezca). En resumen, el blog aboga por tener un MultiButtonAttributeatributo personalizado para permitir la diferenciación entre los botones de envío. En realidad es una buena idea.
Se fue la codificación el
1
Y si Arnis L.hubiera seguido el mismo consejo, es posible que haya notado que él proporcionó exactamente el mismo enlace 4 años antes:>
Gone Coding
3
// Buttons
<input name="submit" type="submit" id="submit" value="Save" />
<input name="process" type="submit" id="process" value="Process" />

// Controller
[HttpPost]
public ActionResult index(FormCollection collection)
{
    string submitType = "unknown";

    if(collection["submit"] != null)
    {
        submitType = "submit";
    }
    else if (collection["process"] != null)
    {
        submitType = "process";
    }

} // End of the index method
Fredrik Stigsson
fuente
Esta es una solución superior a todo lo demás publicado ya que permite que los datos de formularios muy complejos se pasen de manera consistente sin conjuntos de parámetros personalizados en cada acción, lo que permite que la lógica del controlador sea altamente personalizable para formularios complejos. Kudos Fredrik :) ¿Asumo que esta FormCollection pasaría en múltiples formas?
Stokely
Gracias Stokely Puede llamar a este método desde varios formularios; si realiza una llamada ajax, puede incluir muchos formularios en la misma FormCollection.
Fredrik Stigsson
3

Para hacerlo más fácil, diré que puede cambiar sus botones a lo siguiente:

<input name="btnSubmit" type="submit" value="Save" />
<input name="btnProcess" type="submit" value="Process" />

Su controlador:

public ActionResult Create(string btnSubmit, string btnProcess)
{
    if(btnSubmit != null)
       // do something for the Button btnSubmit
    else 
       // do something for the Button btnProcess
}
Zonke-Bonke S'cekeleshe Msibi
fuente
2

Esta publicación no va a responder a Coppermill, porque le han respondido hace mucho tiempo. Mi publicación será útil para quién buscará una solución como esta. En primer lugar, tengo que decir "La solución de WDuffy es totalmente correcta" y funciona bien, pero mi solución (no la mía) se utilizará en otros elementos y hace que la capa de presentación sea más independiente del controlador (porque su controlador depende de "valor" que se utiliza para mostrar la etiqueta del botón, esta función es importante para otros idiomas).

Aquí está mi solución, dales diferentes nombres:

<input type="submit" name="buttonSave" value="Save"/>
<input type="submit" name="buttonProcess" value="Process"/>
<input type="submit" name="buttonCancel" value="Cancel"/>

Y debe especificar los nombres de los botones como argumentos en la acción como a continuación:

public ActionResult Register(string buttonSave, string buttonProcess, string buttonCancel)
{
    if (buttonSave!= null)
    {
        //save is pressed
    }
    if (buttonProcess!= null)
    {
        //Process is pressed
    }
    if (buttonCancel!= null)
    {
        //Cancel is pressed
    }
}

cuando el usuario envía la página usando uno de los botones, solo uno de los argumentos tendrá valor. Supongo que esto será útil para otros.

Actualizar

Esta respuesta es bastante antigua y en realidad reconsidero mi opinión. tal vez la solución anterior sea buena para la situación que pasa el parámetro a las propiedades del modelo. no se molesten y tomen la mejor solución para su proyecto.

AAAA
fuente
Algunas críticas constructivas: esto está bien cubierto por las respuestas existentes a partir de su publicación. Además, esto no escala bien. HTML solo publicará el input[type=submit]valor que se activó, por lo que todos los modelos pueden vincularse a una propiedad con la misma name(ej. action) Y luego puede diferenciar los botones en función valuede esa cadena sin la necesidad de introducir tantas variables en su firma . Por favor, tómese un tiempo para pensar en formatear / sangrar antes de publicar.
KyleMit
0

¿No puedes averiguarlo usando Request.Form Collection? Si se hace clic en el proceso, request.form ["proceso"] no estará vacío

chugh97
fuente
0

Dé el nombre a ambos botones y obtenga el cheque del valor del formulario.

<div>
   <input name="submitButton" type="submit" value="Register" />
</div>

<div>
   <input name="cancelButton" type="submit" value="Cancel" />
</div>

En el lado del controlador:

public ActionResult Save(FormCollection form)
{
 if (this.httpContext.Request.Form["cancelButton"] !=null)
 {
   // return to the action;
 }

else if(this.httpContext.Request.Form["submitButton"] !=null)
 {
   // save the oprtation and retrun to the action;
 }
}
Aniket Sharma
fuente
0

En las páginas Core 2.2 Razor, esta sintaxis funciona:

    <button type="submit" name="Submit">Save</button>
    <button type="submit" name="Cancel">Cancel</button>
public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
        return Page();
    var sub = Request.Form["Submit"];
    var can = Request.Form["Cancel"];
    if (sub.Count > 0)
       {
       .......
Sobras
fuente
Puede funcionar, pero prefiero el parámetro a la string submitescritura string submit = Request.Form["Submit"];. Uno de los mayores beneficios de Razor Pages y / o MVC es la legibilidad de los métodos, de lo contrario podría ser PHP.
yzorg