MVC cujo botão enviar foi pressionado

127

Eu tenho dois botões no meu formulário MVC:

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

Na ação do meu controlador, como sei qual foi pressionado?

Coppermill
fonte
Por que não adicionar eventos onclick a esses botões que vão para sua própria chamada AJAX e para os métodos apropriados? ou seja <input name="submit" type="submit" id="submit" value="Save" onclick="saveMethod" />:?
ragerory

Respostas:

168

Nomeie os dois botões de envio da mesma forma

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

Em seguida, no seu controlador, obtenha o valor de envio. Somente o botão clicado passará seu valor.

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

É claro que você pode avaliar esse valor para executar operações diferentes com um bloco de chave.

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
fonte
13
Cuidado com os problemas que a localização poderia trazer para esta solução, para a qual a solução da Darin não é suscetível.
Richard Szalay
Duas entradas com o mesmo nome resultam em uma matriz sendo postada com um elemento para cada valor, não um valor único, como implícito. Então, eu gostaria de poder dizer o contrário, já que estava esperando / tentando usar isso, mas isso não funciona.
Christopher King
1
@RichardSzalay - você não poderia simplesmente usar <button type="submit" name="action" value="draft"> Internationalized Save Text </button> para fins i18n, assim que a corda enfrentando usuário é personalizável, e nomes de forma elemento nunca são expostos diretamente ao usuário (o que é estranho por si só)
KyleMit
48
<input name="submit" type="submit" id="submit" value="Save" />
<input name="process" type="submit" id="process" value="Process" />

E na ação do seu controlador:

public ActionResult SomeAction(string submit)
{
    if (!string.IsNullOrEmpty(submit))
    {
        // Save was pressed
    }
    else
    {
        // Process was pressed
    }
}
Darin Dimitrov
fonte
1
Eu imagino que mais botões possam ser adicionados simplesmente adicionando-o à lista de parâmetros e nomeando-o corretamente. Ótima solução!
GONeale 30/08/11
35

esta é uma resposta melhor, para que possamos ter texto e valor para um botão:

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>

e o controlador:

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

em suma, é um botão SUBMIT, mas você escolhe o nome usando o atributo name, é ainda mais poderoso porque você não é obrigado a enviar o nome ou ao botão nos parâmetros do método do controlador, pode chamá-lo como quiser ...

Yakir Manor
fonte
Graças Sir, isso é exatamente o que eu preciso
oHoodie
Isso é interrompido se você tiver um sistema multilíngue que altera o valor do botão de acordo com o idioma.
Dave Tapson
Dave - Acho que ninguém codificaria um sistema como esse. É como localizar os nomes de seus controladores ou de funções. O valor do botão é apenas para uso no servidor - ele não é exibido em lugar nenhum e não precisa ser localizado.
NickG 25/06
20

você pode identificar o seu botão a partir da etiqueta de nome como abaixo. Você precisa verificar assim no seu controlador

if (Request.Form["submit"] != null)
{
//Write your code here
}
else if (Request.Form["process"] != null)
{
//Write your code here
}
Kinjal Gohil
fonte
isso é muito útil em situações em que você não deseja passar o nome do botão para o resultado da ação posterior.
Yogihosting 03/04
Nesse cenário, pode ser mais complicado zombar da classe Request no teste de unidade.
Muflix
6

Aqui está uma maneira realmente agradável e simples de fazê-lo, com instruções muito fáceis de seguir usando um MultiButtonAttribute personalizado:

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

Para resumir, faça seus botões de envio como este:

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

Suas ações 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");
} 

E crie esta classe:

[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
fonte
1
Sempre é melhor resumir um link referenciado (no dia em que o blog desaparecer). Em resumo, o blog recomenda ter um MultiButtonAttributeatributo personalizado para permitir a diferenciação entre os botões de envio. Na verdade, é uma ótima idéia.
Gone Coding
1
E se Arnis L.tivesse seguido o mesmo conselho, você pode ter notado que ele forneceu exatamente o mesmo link de 4 anos antes:>
Longe de Codificação
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
fonte
Essa é uma solução superior a tudo o mais postado, pois permite que dados de formulário muito complexos sejam transmitidos consistentemente sem conjuntos de parâmetros personalizados em cada ação, permitindo que a lógica do controlador seja altamente personalizável para formulários complexos. Parabéns Fredrik :) Presumo que este FormCollection passaria em vários formulários?
Stokely
Obrigado Stokely. Você pode chamar esse método de vários formulários; se fizer uma chamada ajax, poderá incluir muitos formulários no mesmo FormCollection.
Fredrik Stigsson
3

Para facilitar, direi que você pode alterar seus botões para o seguinte:

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

O seu 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
fonte
2

Este post não vai responder a Coppermill, porque ele já foi respondido há muito tempo. Minha postagem será útil para quem buscará uma solução como essa. Antes de tudo, tenho que dizer "A solução do WDuffy está totalmente correta" e funciona bem, mas minha solução (que não é minha) será usada em outros elementos e torna a camada de apresentação mais independente do controlador (porque seu controlador depende de "value", usado para mostrar o rótulo do botão, esse recurso é importante para outros idiomas.).

Aqui está a minha solução, dê-lhes nomes diferentes:

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

E você deve especificar os nomes dos botões como argumentos na ação como abaixo:

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

quando o usuário envia a página usando um dos botões, apenas um dos argumentos terá valor. Eu acho que isso será útil para os outros.

Atualizar

Essa resposta é bastante antiga e eu realmente reconsiderei minha opinião. talvez a solução acima seja boa para situações que passam parâmetros às propriedades do modelo. não se incomode e tome a melhor solução para o seu projeto.

AAAA
fonte
Algumas críticas construtivas: isso é bem coberto pelas respostas existentes desde a sua publicação. Além disso, isso não escala bem. O HTML postará apenas de volta o input[type=submit]valor que foi acionado, para que todos possam vincular o modelo a uma propriedade com o mesmo name(ex. action) E, em seguida, você possa diferenciar os botões com base na valuesequência dessa sequência, sem a necessidade de introduzir tantas variáveis ​​em sua assinatura . Também reserve um tempo para pensar em formatação / recuo antes de postar.
KyleMit
0

Você não consegue descobrir usando o Request.Form Collection? Se clicar em processo, o request.form ["process"] não ficará vazio

chugh97
fonte
0

Dê o nome aos dois botões e obtenha o valor do formulário.

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

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

No lado do 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
fonte
0

Nas páginas do Core 2.2 Razor, esta sintaxe 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)
       {
       .......
Leftware
fonte
Pode funcionar, mas eu prefiro parâmetro string submitvs escrita string submit = Request.Form["Submit"];. Um dos maiores benefícios do Razor Pages e / ou MVC é a legibilidade dos métodos; caso contrário, poderia ser PHP.
yzorg 23/06