MVC dont le bouton d'envoi a été enfoncé


128

J'ai deux boutons sur mon formulaire MVC:

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

À partir de mon action de contrôleur, comment savoir lequel a été pressé?


Pourquoi ne pas simplement ajouter des événements onclick à ces boutons qui vont à leur propre appel AJAX qui ira à leurs méthodes appropriées? ie <input name="submit" type="submit" id="submit" value="Save" onclick="saveMethod" />:?
ragerory

Réponses:


169

Nommez vos deux boutons d'envoi de la même manière

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

Ensuite, dans votre contrôleur, obtenez la valeur de submit. Seul le bouton cliqué passera sa valeur.

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

Vous pouvez bien sûr évaluer cette valeur pour effectuer différentes opérations avec un bloc de commutation.

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
Méfiez-vous des problèmes que la localisation pourrait apporter à cette solution, auxquels la solution de Darin n'est pas sensible.
Richard Szalay

Deux entrées portant le même nom entraînent la publication d'un tableau avec un élément pour chaque valeur, pas une seule valeur comme implicite. Donc j'aurais aimé pouvoir dire le contraire puisque j'espérais / essayais d'utiliser ceci, mais cela ne fonctionne pas.
Christopher King

1
@RichardSzalay - ne pourriez-vous pas utiliser uniquement <button type="submit" name="action" value="draft"> Internationalized Save Text </button>à des fins i18n, de sorte que la chaîne face à l'utilisateur est personnalisable et les noms des éléments de formulaire ne sont jamais directement exposés à l'utilisateur (ce qui est étrange en soi)
KyleMit

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

Et dans l'action de votre contrôleur:

public ActionResult SomeAction(string submit)
{
    if (!string.IsNullOrEmpty(submit))
    {
        // Save was pressed
    }
    else
    {
        // Process was pressed
    }
}

1
J'imagine que plus de boutons pourraient être ajoutés en l'ajoutant simplement à la liste des paramètres et en le nommant correctement. Belle solution!
GONeale

35

c'est une meilleure réponse, nous pouvons donc avoir à la fois du texte et une valeur pour un bouton:

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>

et le contrôleur:

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

en bref c'est un bouton SUBMIT mais vous choisissez le nom en utilisant l'attribut name, c'est encore plus puissant car vous n'êtes pas obligé de soumettre le nom ou de bouton dans les paramètres de la méthode du contrôleur, vous pouvez l'appeler comme vous le souhaitez ...


Merci Monsieur, c'est exactement ce dont j'ai besoin
oHoodie

Cela s'arrête si vous avez un système multilingue qui change la valeur du bouton en fonction de la langue.
Dave Tapson

Dave - Je ne pense pas que quiconque coderait un système comme celui-là. C'est comme localiser les noms de vos contrôleurs ou de vos fonctions. La valeur du bouton est pour une utilisation côté serveur uniquement - il ne s'affiche nulle part et n'a pas besoin d'être localisé.
NickG

20

vous pouvez identifier votre bouton à partir de là étiquette de nom comme ci-dessous, vous devez vérifier comme ça dans votre contrôleur

if (Request.Form["submit"] != null)
{
//Write your code here
}
else if (Request.Form["process"] != null)
{
//Write your code here
}

ceci est très utile dans les situations où vous ne voulez pas passer le nom du bouton au résultat de l'action de publication.
yogihosting

dans ce scénario, il peut être plus compliqué de simuler la classe Request dans le test unitaire.
Muflix

6

Voici une façon vraiment simple et agréable de le faire avec des instructions vraiment faciles à suivre à l'aide d'un MultiButtonAttribute personnalisé:

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

Pour résumer, créez vos boutons de soumission comme ceci:

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

Vos actions comme ceci:

[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");
} 

Et créez cette 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;
    }
}

1
Il est toujours préférable de résumer un lien référencé (pour le jour où le blog disparaît). En résumé, ce blog préconise d'avoir un MultiButtonAttributeattribut personnalisé pour permettre de différencier les boutons d'envoi. En fait, une bonne idée.
Fini le codage

1
Et s'il Arnis L.avait suivi le même conseil, vous avez peut-être remarqué qu'il a fourni exactement le même lien 4 ans plus tôt:>
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

Il s'agit d'une solution supérieure à tout ce qui est publié, car elle permet de transmettre des données de formulaire très complexes de manière cohérente sans jeux de paramètres personnalisés dans chaque action, ce qui permet à la logique du contrôleur d'être hautement personnalisable pour les formulaires complexes. Félicitations Fredrik :) Je suppose que ce FormCollection passerait sous plusieurs formes?
Stokely

Merci Stokely. Vous pouvez appeler cette méthode à partir de plusieurs formulaires, si vous effectuez un appel ajax, vous pouvez inclure plusieurs formulaires dans le même FormCollection.
Fredrik Stigsson

3

Pour faciliter les choses, je dirai que vous pouvez modifier vos boutons comme suit:

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

Votre contrôleur:

public ActionResult Create(string btnSubmit, string btnProcess)
{
    if(btnSubmit != null)
       // do something for the Button btnSubmit
    else 
       // do something for the Button btnProcess
}

2

Ce message ne répondra pas à Coppermill, car on lui a répondu il y a longtemps. Mon message sera utile pour qui recherchera une solution comme celle-ci. Tout d'abord, je dois dire que "la solution de WDuffy est totalement correcte" et cela fonctionne bien, mais ma solution (pas vraiment la mienne) sera utilisée dans d'autres éléments et cela rend la couche de présentation plus indépendante du contrôleur (parce que votre contrôleur dépend de "valeur" qui est utilisée pour afficher l'étiquette du bouton, cette fonctionnalité est importante pour les autres langues.).

Voici ma solution, donnez-leur des noms différents:

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

Et vous devez spécifier les noms des boutons comme arguments dans l'action comme ci-dessous:

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

lorsque l'utilisateur soumet la page à l'aide de l'un des boutons, un seul des arguments aura une valeur. Je suppose que cela sera utile pour les autres.

Mettre à jour

Cette réponse est assez ancienne et je reconsidère en fait mon opinion. peut-être que la solution ci-dessus est bonne pour la situation qui passe le paramètre aux propriétés du modèle. ne vous inquiétez pas et prenez la meilleure solution pour votre projet.


Quelques critiques constructives le long: ceci est bien couvert par les réponses existantes au moment de votre publication. De plus, cela ne s'adapte pas bien. HTML ne publiera que la input[type=submit]valeur qui a été déclenchée, afin qu'ils puissent tous se lier au modèle à une propriété avec le même name(ex. action) Et ensuite vous pouvez différencier les boutons en fonction de la valuede cette chaîne sans avoir besoin d'introduire autant de variables dans votre signature . Veuillez également prendre le temps de réfléchir au formatage / retrait avant de publier.
KyleMit

0

Vous ne pouvez pas le savoir en utilisant Request.Form Collection? Si le processus est cliqué, request.form ["process"] ne sera pas vide


0

Donnez le nom aux deux boutons et obtenez le contrôle de la valeur du formulaire.

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

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

Côté contrôleur:

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

Dans les pages Razor Core 2.2, cette syntaxe fonctionne:

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

Cela pourrait fonctionner, mais je préfère les paramètres à l' string submitécriture string submit = Request.Form["Submit"];. L'un des plus grands avantages de Razor Pages et / ou MVC est la lisibilité des méthodes, sinon cela pourrait être PHP.
yzorg le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.