Question Comment gérez-vous plusieurs boutons d'envoi dans ASP.NET MVC Framework?


Existe-t-il un moyen simple de gérer plusieurs boutons d'envoi à partir du même formulaire? Exemple:

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

Une idée de comment faire cela dans ASP.NET Framework Beta? Tous les exemples que j'ai googlé pour avoir des boutons simples en eux.


652
2018-01-14 11:58


origine


Réponses:


Voici une solution basée sur les attributs pour la plupart du temps au problème de bouton d'envoi multiple basé fortement sur le message et les commentaires 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;
    }
}

le rasoir:

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

et contrôleur:

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

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

Mettre à jour:  Pages de rasoir cherche à fournir la même fonctionnalité hors de la boîte. Pour un nouveau développement, cela peut être préférable.


550
2017-08-18 17:00



Donnez un nom à vos boutons de soumission, puis inspectez la valeur soumise dans votre méthode de contrôleur:

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

poster à

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

}

MODIFIER:

Pour étendre cette approche à travailler avec des sites localisés, isolez vos messages ailleurs (par exemple, en compilant un fichier de ressources dans une classe de ressources fortement typée)

Ensuite, modifiez le code pour qu'il fonctionne comme:

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

et votre contrôleur devrait ressembler à ceci:

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

438
2018-01-14 14:02



Vous pouvez vérifier le nom dans l'action comme cela a été mentionné, mais vous pourriez considérer si c'est un bon design. C'est une bonne idée de considérer la responsabilité de l'action et de ne pas trop coupler cette conception aux aspects de l'interface utilisateur comme les noms de boutons. Alors pensez à utiliser 2 formes et 2 actions:

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

En outre, dans le cas de "Annuler", vous ne traitez généralement pas le formulaire et vous redirigez vers une nouvelle URL. Dans ce cas, vous n'avez pas besoin de soumettre le formulaire et vous avez juste besoin d'un lien:

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

115
2018-01-14 12:26



Eilon suggère que vous pouvez le faire comme ceci:

Si vous avez plus d'un bouton,   peut les distinguer en donnant   chaque bouton un nom:

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

Dans la méthode d'action de votre contrôleur, vous   peut ajouter des paramètres nommés après le   Noms de tag d'entrée HTML:

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

Si une valeur est affichée dans l'un des   ces paramètres, cela signifie que   bouton était celui qui a été cliqué.   Le navigateur Web affichera seulement une valeur   pour le un bouton qui a été cliqué.   Toutes les autres valeurs seront nulles.

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

J'aime cette méthode car elle ne repose pas sur la propriété value des boutons submit qui est plus susceptible de changer que les noms assignés et ne nécessite pas l'activation de javascript

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


92
2018-01-20 21:30



Je viens d'écrire un post à ce sujet: Plusieurs boutons de soumission avec ASP.NET MVC:

Fondamentalement, au lieu d'utiliser ActionMethodSelectorAttribute, J'utilise ActionNameSelectorAttribute, ce qui me permet de prétendre que le nom de l'action est ce que je veux qu'il soit. Heureusement, ActionNameSelectorAttribute ne me fait pas seulement spécifier le nom de l'action, mais je peux choisir si l'action en cours correspond à la requête.

Donc il y a ma classe (d'ailleurs je n'aime pas trop le nom):

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

Pour utiliser, il suffit de définir un formulaire comme celui-ci:

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

et contrôleur avec deux méthodes

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

    [HttpParamAction]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Publish(…) {
        //…
    } 
}

Comme vous le voyez, l'attribut ne vous oblige pas à spécifier quoi que ce soit. De plus, le nom des boutons est traduit directement dans les noms de méthodes. De plus (je n'ai pas essayé cela), cela devrait aussi fonctionner comme des actions normales, donc vous pouvez poster sur n'importe lequel d'entre eux directement.


39
2018-03-15 19:03



Je suggère des parties intéressées jetez un oeil à la solution de Maarten Balliauw. Je pense que c'est très élégant.

Au cas où le lien disparait, il utilise le MultiButton attribut appliqué à une action du contrôleur pour indiquer à quel clic de bouton cette action doit se rapporter.


34
2018-04-22 15:36



c'est court et suite:

Il a été répondu par Jeroen Dop

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

et fais comme ça dans le code behinde

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

Bonne chance.


23
2018-05-28 09:41



Vous devriez pouvoir nommer les boutons et leur donner une valeur; puis mappez ce nom en tant qu'argument à l'action. Vous pouvez également utiliser 2 liens d'action séparés ou 2 formulaires.


19
2018-01-14 12:07



Vous pourriez écrire:

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

Et puis dans la page vérifiez si le nom == "Envoyer" ou nom == "Annuler" ...


12
2018-01-14 12:11



Quelque chose que je n'aime pas à propos d'ActionSelectName est que IsValidName est appelé pour chaque méthode d'action dans le contrôleur; Je ne sais pas pourquoi cela fonctionne de cette façon. J'aime une solution où chaque bouton a un nom différent basé sur ce qu'il fait, mais je n'aime pas le fait que vous devez avoir autant de paramètres dans la méthode d'action que de boutons dans le formulaire. J'ai créé une énumération pour tous les types de boutons:

public enum ButtonType
{
    Submit,
    Cancel,
    Delete
}

Au lieu de ActionSelectName, j'utilise 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;
            }
        }
    }
}

Le filtre trouvera le nom du bouton dans les données du formulaire et si le nom du bouton correspond à l'un des types de boutons définis dans l'énumération, il trouvera le paramètre ButtonType parmi les paramètres d'action:

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

et puis dans les vues, je peux utiliser:

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

11
2017-12-15 11:53



Voici ce qui fonctionne le mieux pour moi:

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

10
2017-12-22 00:46