61

I am using ASP.Net MVC 4. I have multiple buttons on a view.. At present I am calling the same action method; and I am distinguishing the clicked button using a name attribute.

@using (Html.BeginForm("Submit", "SearchDisplay", new { id = Model == null ? Guid.NewGuid().ToString() : Model.SavedSearch }, FormMethod.Post))
{
    <div class="leftSideDiv">
        <input type="submit" id="btnExport" class="exporttoexcelButton" 
        name="Command" value="Export to Excel" />
    </div>

    <div class="pageWrapperForSearchSubmit">
        <input type="submit" class="submitButton" 
         value="Submit" id="btnSubmitChange" />
    </div>
}

//ACTION

    [HttpPost]
    public ActionResult Submit(SearchCostPage searchModel, string Command)
    {
        SessionHelper.ProjectCase = searchModel.ProjectCaseNumber;

        if (string.Equals(Command, Constants.SearchPage.ExportToExcel))
        {

        }
   }

QUESTIONS

  1. Is there a way to direct to different POST action methods on different button clicks (without custom routing)?
  2. If there is no way without custom routing, how can we do it with custom routing?

References:

  1. Jimmy Bogard - Cleaning up POSTs in ASP.NET MVC
LCJ
  • 22,196
  • 67
  • 260
  • 418
  • 1
    JS will allow you to pre-process your submit request, it doesn't mean you can't still have a full postback. – James Jan 14 '14 at 15:22
  • 1
    I've edited your question's title to make it more accurate, and added a simple, working answer (working in production in some of my projects). – JotaBe Jan 14 '14 at 16:33
  • Why not go the multiple submit button route a la https://stackoverflow.com/questions/442704/how-do-you-handle-multiple-submit-buttons-in-asp-net-mvc-framework?noredirect=1&lq=1 – Paul Zahra May 10 '18 at 10:53
  • [This Tutorial](https://medium.com/@bahreinihooman/submitting-a-form-to-different-action-methods-in-asp-net-mvc-c7a06e3c2766) might help. – Hooman Bahreini Sep 11 '19 at 07:41

4 Answers4

85

You can choose the url where the form must be posted (and thus, the invoked action) in different ways, depending on the browser support:

In this way you don't need to do anything special on the server side.

Of course, you can use Url extensions methods in your Razor to specify the form action.

For browsers supporting HMTL5: simply define your submit buttons like this:

<input type='submit' value='...' formaction='@Url.Action(...)' />

For older browsers I recommend using an unobtrusive script like this (include it in your "master layout"):

$(document).on('click', '[type="submit"][data-form-action]', function (event) {
  var $this = $(this);
  var formAction = $this.attr('data-form-action');
  $this.closest('form').attr('action', formAction);
});

NOTE: This script will handle the click for any element in the page that has type=submit and data-form-action attributes. When this happens, it takes the value of data-form-action attribute and set the containing form's action to the value of this attribute. As it's a delegated event, it will work even for HTML loaded using AJAX, without taking extra steps.

Then you simply have to add a data-form-action attribute with the desired action URL to your button, like this:

<input type='submit' data-form-action='@Url.Action(...)' value='...'/>

Note that clicking the button changes the form's action, and, right after that, the browser posts the form to the desired action.

As you can see, this requires no custom routing, you can use the standard Url extension methods, and you have nothing special to do in modern browsers.

quadfinity
  • 877
  • 1
  • 8
  • 9
JotaBe
  • 38,030
  • 8
  • 98
  • 117
  • 1
    I'm afraid I cannot. I did this myself. Please, try it, and if you have any doubt write a comment and I'll help you by improving my answer. Although I think kit's quite clear, and you'll get it working soon. – JotaBe Jan 16 '14 at 09:42
  • 1
    Could you use both methods simultaneously to support multiple browsers? Or must you choose one or the other? – navig8tr May 25 '16 at 00:51
  • 2
    The JavaScript solution supports both old and new browsers provided that JavaScript isn't disabled. Using both techniques at the same time, which is possible, would also cover the case of HTML5 compatible browsers with JavaScript disabled. – JotaBe May 25 '16 at 08:59
22

BEST ANSWER 1:

ActionNameSelectorAttribute mentioned in

  1. How do you handle multiple submit buttons in ASP.NET MVC Framework?

  2. ASP.Net MVC 4 Form with 2 submit buttons/actions

http://weblogs.asp.net/scottgu/archive/2007/12/09/asp-net-mvc-framework-part-4-handling-form-edit-and-post-scenarios.aspx

ANSWER 2

Reference: dotnet-tricks - Handling multiple submit buttons on the same form - MVC Razor

Second Approach

Adding a new Form for handling Cancel button click. Now, on Cancel button click we will post the second form and will redirect to the home page.

Third Approach: Client Script

<button name="ClientCancel" type="button" 
    onclick=" document.location.href = $('#cancelUrl').attr('href');">Cancel (Client Side)
</button>
<a id="cancelUrl" href="@Html.AttributeEncode(Url.Action("Index", "Home"))" 
style="display:none;"></a>
Community
  • 1
  • 1
LCJ
  • 22,196
  • 67
  • 260
  • 418
5

This sounds to me like what you have is one command with 2 outputs, I would opt for making the change in both client and server for this.

At the client, use JS to build up the URL you want to post to (use JQuery for simplicity) i.e.

<script type="text/javascript">
    $(function() {
        // this code detects a button click and sets an `option` attribute
        // in the form to be the `name` attribute of whichever button was clicked
        $('form input[type=submit]').click(function() {
            var $form = $('form');
            form.removeAttr('option');
            form.attr('option', $(this).attr('name'));
        });
        // this code updates the URL before the form is submitted
        $("form").submit(function(e) { 
            var option = $(this).attr("option");
            if (option) {
                e.preventDefault();
                var currentUrl = $(this).attr("action");
                $(this).attr('action', currentUrl + "/" + option).submit();     
            }
        });
    });
</script>
...
<input type="submit" ... />
<input type="submit" name="excel" ... />

Now at the server side we can add a new route to handle the excel request

routes.MapRoute(
    name: "ExcelExport",
    url: "SearchDisplay/Submit/excel",
    defaults: new
    {
        controller = "SearchDisplay",
        action = "SubmitExcel",
    });

You can setup 2 distinct actions

public ActionResult SubmitExcel(SearchCostPage model)
{
   ...
}

public ActionResult Submit(SearchCostPage model)
{
   ...
}

Or you can use the ActionName attribute as an alias

public ActionResult Submit(SearchCostPage model)
{
   ...
}

[ActionName("SubmitExcel")]
public ActionResult Submit(SearchCostPage model)
{
   ...
}
James
  • 80,725
  • 18
  • 167
  • 237
3

you can use ajax calls to call different methods without a postback

$.ajax({
    type: "POST",
     url: "@(Url.Action("Action", "Controller"))",
     data: {id: 'id', id1: 'id1' },
     contentType: "application/json; charset=utf-8",
     cache: false,
     async: true,
     success: function (result) {
        //do something
     }
});
Matt Bodily
  • 6,403
  • 4
  • 29
  • 48