views:

683

answers:

9

In general, is it possible to have two different buttons within the same form that post to different controller actions in ASP.NET MVC?

I am essentially trying to have two input (type="button") tags in the same form, but I want them to perform different controller actions. I would like to do this in a few cases because I think it provides a good aesthetic to be able to click buttons as opposed to hyperlinks. Is there a way to do this or should I design it differently?

+6  A: 

Not really possible without using Javascript. With Javascript you'd just have to define different click handlers that invoked the proper action.

 $(function() {
      $('#button1').click( function() {
          $(form).attr( 'action', '<% Url.Action( "action1" ) %>' )
                 .submit();
          return false; // prevent default submission
      });
      $('#button2').click( function() {
           $(form).attr( 'action', '<% Url.Action( "action2" ) %>' )
                 .submit();
          return false; // prevent default submission
      });
});
tvanfosson
Please note that this example is using jQuery... an excellent choice IMO.
Chris Missal
A: 

This has nothing to do with ASP.NET MVC but with html. The only way I see how you could do this is by modifying the action attribute of the form tag using javascript on submission of the form by checking which button was pressed.

olle
A: 

Well there are a few ways you could handle this. Assuming you aren't sending data with the button click I'd go with option 3. If data must be included then consider option 1 with some sort of temporary data store (like TempData).

  1. One form posts to one controller action on submit and the controller action checks which button was clicked and then dispatches a RedirectToAction(). (Not great)
  2. Multiple forms on one page post to multiple controller actions (Better)
  3. Inside or outside a form create an input type="button" and give it an onclick handler that redirects the user to a controller action (Best)
Nathan Taylor
Redirecting won't maintain the data being passed. You'd have to store the data in TempData to retain it.
tvanfosson
Good point tvan.
Nathan Taylor
+1  A: 

Some thoughts about handling this in the browser:

  • You can use links which are styled to look like buttons. This is easy to do, either with images or by putting the link in a block element with borders.
  • You can use two buttons which don't directly submit; they instead call a javascript function that sets the form action before submitting.
Jon Galloway
Links don't submit forms. In case they do (through JS) - then where's the difference between 1st and 2nd approach?
Arnis L.
Links can perform a get request, and you could use JavaScript to build the URL. But, you're right - if you need form elements to be submitted, there's no real benefit to links.
Jon Galloway
Styling links and buttons to look the same is eventually the direction I went. Thanks for the suggestion!
YeahStu
A: 
grenade
A better answer would be "although this is doable in way X, I suggest you go back and rethink about what the core problem you are trying to solve is, and if using this method is what you NEED or what you WANT. Things can get very messy very quickly when you start doing things in manner X"
MunkiPhD
I'm starting to dislike this picture. It's like everywhere.
Arnis L.
@MunkiPhD You managed to derive and articulate my entire point so I think the picture must have said it's thousand words.
grenade
@Arnis L: Fair point. On those grounds it's worth a down vote or two.
grenade
A: 

Haven't tried this, but given the ID of the clicked button does get sent VIA http POST, you could probably do something like:

<input type="submit" name="GO" ID="GO" value="GO BUTTON" />
<input type="submit" name="STOP" ID="STOP" value="STOP BUTTON" />

Then on the mvc end, just have two methods, one with a go parameter, one with a stop parameter.

Wyatt Barnett
A: 

Method #1

How about using two different forms wrapping the buttons, then using CSS to position one of them so that it appears (visually) to be inside the "main" form?

A really quick example:

<fieldset id="CombinedForm">

<form ... action="Method1">
  ...form stuff here...
  <input id="Button1" type="submit" value="Do something">
</form>

<form ... action="Method2">
  ...form stuff here...
  <input id="Button2" type="submit" value="Do something else">
</form>

</fieldset>

...Then using CSS as follows:

#CombinedForm {
  position: relative;
  padding-bottom: 2em; /* leave space for buttons */
}

#Button1, #Button2 {
  position: absolute;
  bottom: 0;
}

#Button1 {
  left: 0;
}

#Button2 {
  right: 0;
}

The result should be that you have a fieldset or div which looks like a form, having two actual HTML forms inside it, and two buttons which are positioned within the parent box, yet submitting to different locations.

Method #2

Another method occurs: have both buttons in the same form, pointing to one controller action, that then decides (based on the value of the button clicked) which action to redirect to.

Keith Williams
#1 - most likely those buttons needs to submit the same data, so - it won't work. #2 just feels awkward - doesn't it? :)
Arnis L.
@Amis - it all feels a bit awkward :p But if they're submitting the same data, and the only difference is what to do with it, then to me that sounds like it's the same method with a different switch. TBH, this is more than likely going to be used for OK/Cancel buttons, where cancel doesn't need to submit any data at all.
Keith Williams
A: 

Its not Javascript required...

how about this

public ActionResult DoSomething()
{
     // Some business logic
     TempData["PostedFormValues"] = Request.Form;
     if (Request.Form("ButtonA") != null)
     {
        return RedirectToAction("ActionA", RouteData.Values);
     }
     return RedirectToAction("ActionB", RouteData.Values);
}

Hurricanepkt
A: 

If all you want is something like OK & Cancel buttons, then have a look at this post by David Findley.

I'm using this method on my Edit view, where I have an Edit button and a Delete button. The delete button only requires the Id of the item. In the code below you can see that I've named my attribute "AcceptFormValueAttribute". This is method good for me, because my Delete [Get] action just shows a message asking for confirmation, so needs the redirect.

 [ActionName("Edit")]
 [AcceptFormValue(Name = "Action", Value = "Delete")]
 [AcceptVerbs(HttpVerbs.Post)]
 [ValidateAntiForgeryToken]
 public ActionResult EditDelete(int? id)
 {
  return RedirectToAction("Delete", new { id = id });
 }
jimr