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?


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

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

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 ...


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
}

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

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

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
}

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.


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


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

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)
       {
       .......

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.