21

I am currently having an issue with multiple action buttons being in the same form.

The first button would perform verification while the second button would save profile. The third would simple redirect the user out of the page, but they are still required to go through controller some tracking purposes. Last button is delete. Because they are placed together and I do need ModelBinding passed through POST, it's impossible to separate them into multiple forms.

Currently, in order to differentiate which action is being clicked, I have a hidden input in my form and onclick, javascript would update the hidden input so that it will be passed back to the controller.

The reason I did this was because for some weird reasons, FormCollection doesn't want to hold my submit values. I tried accessing buttons in controller via

formCollection["verify"]

But it turns out to be null. Both id and name of the input submit is set to verify.

I also tried a lot of other suggestions like this and this but to no avail. Is there a better approach to my problem without using javascript to alter hidden inputs?

Mr. 笑哥
  • 283
  • 1
  • 5
  • 15

3 Answers3

35

The best approach is to have separate actions handling the different button calls as explained in this article.

If you want to have one ugly action doing all the stuff then you could give your submit buttons names:

@using (Html.BeginForm())
{
    ... input fields for the model

    <button type="submit" name="btn" value="verify">Verify data</button>
    <button type="submit" name="btn" value="save">Save data</button>    
    <button type="submit" name="btn" value="redirect">Redirect</button>
}

You don't need any hidden fields or javascript. And then in your controller action you would check for the value of the btn parameter (which obviously will be part of you view model):

[HttpPost]
public ActionResult Foo(MyViewsModel model)
{
    if (model.Btn == "verify")
    {
        // the Verify button was clicked
    }
    else if (model.Btn == "save")
    {
        // the Save button was clicked
    } 
    else if (model.Btn == "redirect")
    {
        // the Redirect button was clicked
    } 
    else
    {
        // ??? throw
    }

    ...
}

Of course if you follow my advice and separate your actions (as outlined in the article):

@using (Html.BeginForm("Action", "Home"))
{
    ... input fields for the model

    <input type="submit" name="verify" value="Verify data" />
    <input type="submit" name="save" value="Save data" />
    <input type="submit" name="redirect" value="Redirect" />
}

and then:

[HttpParamAction]
[HttpPost]
public ActionResult Verify(MyViewModel model)
{
    ...
}

[HttpParamAction]
[HttpPost]
public ActionResult Save(MyViewModel model)
{
    ...
}

[HttpParamAction]
[HttpPost]
public ActionResult Redirect(MyViewModel model)
{
    ...
}

which is a far cleaner code which doesn't violate the Single Responsibility Principle.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 1
    I did the exact thing as instructed in your article but to no avail. I placed breakpoints at all 4 ActionResults and none of them are hitting. – Mr. 笑哥 Nov 24 '11 at 23:25
  • @Jon, maybe then you did something wrong since the code shown in the article works perfectly fine for me. Unfortunately without seeing your code it will be difficult to help. – Darin Dimitrov Nov 25 '11 at 07:39
  • Unfortunately, this is company's property. So I can't really show without my superior's permission. – Mr. 笑哥 Nov 25 '11 at 11:57
  • @Jon, well, in this situation all I can do it to wish you good luck in solving the problem. – Darin Dimitrov Nov 25 '11 at 12:03
  • second (cleaner) solution didn't work well for me. When input type names are same as action names, action model input data are always null – Afshar Mohebi Jul 11 '13 at 14:45
1

I do something slightly different;

<input type="submit" name="submit" value="Save Draft" />
<input type="submit" name="submit" value="Publish" />

Then you can get at the values using;

FormCollection["submit"]

Thanks,

Matt

Matt Griffiths
  • 1,142
  • 8
  • 26
  • Problem is, I set a breakpoint at my Action method and hovered over FormCollection, ran through all keys, submit (or save / verify in my case) wasn't part of the keys. – Mr. 笑哥 Nov 24 '11 at 23:37
  • @Jon The problems you are having are very unusual, may I see you [HttpGet] method? – Matt Griffiths Nov 25 '11 at 09:22
  • Indeed, this is very weird. I tried all possibilities, like swapping inputs for buttons but to no avail. It seems, my formCollection only takes non-button values. I added a few other hidden inputs and all of them were posted back to the controller, only the buttons not. – Mr. 笑哥 Nov 25 '11 at 12:03
  • @Jon I have just digested what you have said, and I would encourage you to use the same name for all the submits (like in my example above), and just change the values. Let me know what happens! – Matt Griffiths Nov 25 '11 at 13:43
  • I tried your suggestion, but still not going anywhere. FormCollection is not carrying my submit value across. I tried button type submit and input type submit, neither would pass values back to FormCollection. This is indeed very weird. – Mr. 笑哥 Nov 26 '11 at 07:37
  • @Jon It may seem completely random, but is the button contained within the form? Additionally, do you only have one form on the page? – Matt Griffiths Nov 26 '11 at 23:26
  • Sorry I have been away for some time. Been on holiday. Yes, the button is contained within the form and yes, I only have one form on the page, only one form is required in my case. – Mr. 笑哥 Dec 05 '11 at 23:46
0
<input type="submit" name="nameONE" />
<input type="submit" name="nameTWO" />

            [HttpPost, ActionName("OrginalActionName")]
            [FormValueRequired("nameONE")]
            public ActionResult WhateverYouWantONE(type name)
            {
                code...
            }

            [HttpPost, ActionName("OrginalActionName")]
            [FormValueRequired("nameTWO")]
            public ActionResult WhateverYouWantTWO(type name)
            {
                code...
            }
AZ Chad
  • 1,616
  • 1
  • 15
  • 20