SOLVED: MVC multiple submit buttons in one form

SOLVED: MVC multiple submit buttons in one form

Fix reading submit buttons values in an ASP.Net MVC post action with a remote validation on model properties.

SOLVED: MVC multiple submit buttons in one form

This topic will be discussed with the following structure.

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.

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. 

Let's assume you have a remote validation on the property "SomeProperty" of "SomeModel".

public class SomeModel { [Remote("SomeValidationAction", "SomeController", ErrorMessage="An error occurred")] 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.

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

Did you find this helpful?

Read Next

The following articles are related to solved: mvc multiple submit buttons in one form.

SOLVED: MVC multiple submit buttons in one form
Fady Soliman
Fady SolimanMember since
Jun 22, 2013
Loading...
1 Comment

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.

Contact Us
Share your COMMENT!

Share your thoughts and feedback on SOLVED: MVC multiple submit buttons in one form

Ask any questions directly to Fady Soliman and the community!

By using this channel you approve that you agree on our Terms and Conditions