SOLVED: MVC multiple submit buttons in one form

SOLVED: MVC multiple submit buttons in one form
25 March, 2017
Fady Soliman
1 Comments
5646 Views
 1 user marked as helpfull

SOLVED: MVC multiple submit buttons in one form

One of the biggest advantages of ASP.NET MVC over ASP.NET web forms is that in ASP.NET web forms you can have only one form that runs at server in any single page. This has changed in ASP.NET MVC. You can have N multiple forms with N multiple submit buttons inside any of the forms. This advantage made ASP.NET MVC development more custom, more flexible and reliable.

Multiple submit buttons in Razor

A simple way to achieve this using Razor is to build your form like shown in the following listing.

@model SomeModel

@using (Html.BeginForm("SomeAction", "SomeController", FormMethod.Post))
{
@Html.TextBoxFor(model => model.SomeProperty)
<input type="submit" name="submitButton" value="Value1"/>
<input type="submit" name="submitButton" value="Value2"/>
}

In the previous form, there are 2 submit buttons placed with the same name and the form is posting to a post action called "SomeAction" found in a controller called "SomeController". This form is posting a model of type "SomeModel" with one property called "SomeProperty" that's bound to an input text box using Razor helpers. This part will be discussed later in this post but for now that's all what you need to do in Razor.


Unlimited and free web design guest posts


Multiple submit buttons in post action

Moving on from the Razor part to the post action that's called "SomeAction" as mentioned in the previous section. In the post action all what you need to do is, simply, adding an extra string parameter that's named exactly like the submit buttons' names. The following listing is illustrating that.

[HttpPost]
public ActionResult SomeAction(SomeModel model, string submitButton)
{
switch(submitButton)
{
case "Value1":
break;

case "Value2":
break;
}
}

The submitButton string parameter in the previous listing carries all the submit buttons' values named with the same name allover the form. The SomeModel parameter is your posted model from the action as mentioned in the previous razor section.

An issue with model properties remote validations

Following the previous 2 steps, if you don't have any remote validations on your model properties then you are good to go (you can skip the rest of this post from here but it's good to have an idea about the following issue), but if you do have any remote validation on any model property you will face an issue here. Lets assume you have a remote validation on the property "SomeProperty" of "SomeModel".

public class SomeModel
{
[Remote("SomeValidationAction", "SomeController", ErrorMessage="An error occured")]
public string SomeProperty {set; get;}
}

This remote validation will validate on "SomeProperty" using a server side action called "SomeValidationAction". The remote validation details are out of the scope of this post. Having the remote validation on the property "SomeProperty" of the posted model "SomeModel" will lead to having the "submitButton" string parameter value always as null. After spending hours trying to find a way out of this problem, a solution is found here: http://stackoverflow.com/questions/442704/how-do-you-handle-multiple-submit-buttons-in-asp-net-mvc-framework

Solution

Step 1: Change the name of the submit buttons

As mention in the previous link, you will need to do a slight change in the form Razor code in the first section.

@model SomeModel

@using (Html.BeginForm("SomeAction", "SomeController", FormMethod.Post))
{
@Html.TextBoxFor(model => model.SomeProperty)
<input type="submit" name="action:Value1" value="Value1"/>
<input type="submit" name="action:Value2" value="Value2"/>
}

The first submit button's name is changed from "submitButton" to "action:Value1" and the second button's name is also changed from "submitButton" to "action:Value2". This format is needed to be like that and will be discussed later in this post but all you need to notice now is that the buttons now are having different names.

Step 2: Build an attribute of type ActionNameSelectionAttribute

you will need to build an ActionNameSelectionAttribute.


[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)
{
bool isValidName = false;
string 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;
}
}

Step 3: Split the post action to two actions in your controller

Instead of having one post action as illustrated in the second section, you will need to split them up and marking them with the previous ActionNameSelectionAttribute named "MultipleButton".


[HttpPost]
[MultipleButton(Name = "action", Argument = "Value1")]
public ActionResult SomeAction1(SomeModel model) { ... }

[HttpPost]
[MultipleButton(Name = "action", Argument = "Value2")]
public ActionResult SomeAction2(SomeModel model) { ... }



Now instead of using a switch case inside one action, the action is split into two actions marked by the different argument values used in the submit buttons' names. SomeAction1 is the post action that will handle the post request coming from the submit button whose name is "action:Value1" and SomeAction2 will handle the post request coming from the button whose name is "action:Value2". What did this is the MultipleButton ActionNameSelectionAttribute. This attribute will be discussed in the next section.

The ActionNameSelectionAttribute in details

When you create a new class that inherits from ActionNameSelectionAttribute you will need to override the IsValidName method. In this method you will need to build up a formatted key-value string as in the below line.


string keyValue = string.Format("{0}:{1}", Name, Argument);



The Name and Argument are the properties that are set from the MultipleButton attribute placed over the the action. The following line of code is the core of directing the post request coming from any of the submit buttons to its corresponding post action.




var value = controllerContext.Controller.ValueProvider.GetValue(keyValue);



If the returned value is not null, then you are on the right corresponding post action based on the MultipleButton ActionNameSelectionAttribute attribute's Name and Argument.

You are done

Now you are done solving the remote validation issue along with multiple submit buttons inside one form. Again, if you don't have any remote validations in your model properties then reaching the second section will be sufficient for having multiple buttons working.

04 September, 2013
Fady Soliman
c sharp
1 Comments
5646 Views

Did you find this helpfull?

About The Author

Fady Soliman

An experienced, resourceful and highly motivated IT professional, with a proven record of success in both Stack Development and Software Architecture. Possesses a wealth of transferable skills, including outstanding interpersonal, problem solving and staff management abilities. A capable organizer, quick to grasp – and make good use of – new ideas and information, and reliable and conscientious in all he takes on.

1 Response

  1. Komal Jariwala
    Komal Jariwala25 January, 2014 05:04 AM(reply)
    This soultion is also not working with remote validation. It's calling and seraching for Create action from controller. If i will comment remote validation, then everything will work fine. Please help with remote validation and multiple buttons handling.

leave A Comment