ASP.NET MVC: Hidden field value does not get rendered using HtmlHelper.Hidden

69,719

Solution 1

The helper will first look for POSTed values and use them. As you are posting the form it will pick up the old value of the ID. Your workaround is correct.

Solution 2

ADDENDUM: Multiple HTML Forms, eg, in a Grid

As an addendeum to this issue, one thing to be VERY careful of is with multiple forms on the same page, eg, in a grid, say one generated using Ajax.BeginForm.

You might be tempted to write something along the lines of:

@foreach (var username in Model.TutorUserNames)
        {
            <tr>
                <td>
                    @Html.ActionLink(username, MVC.Admin.TutorEditor.Details(username))
                </td>
                <td>
                    @using (Ajax.BeginForm("DeleteTutor", "Members",
                        new AjaxOptions
                        {
                            UpdateTargetId = "AdminBlock",
                            OnBegin = "isValidPleaseWait",
                            LoadingElementId = "PleaseWait"
                        },
                        new { name = "DeleteTutorForm", id = "DeleteTutorForm" }))
                    {    
                        <input type="submit" value="Delete" />
                        @Html.Hidden("TutorName", username)
                    }
                </td>
            </tr>
        }

The lethal line in here is:

@Html.Hidden("TutorName", username)

... and intend to use TutorName as your action's parameter. EG:

public virtual ActionResult DeleteTutor(string TutorName){...}

If you do this, the nasty surprise you are in for is that Html.Hidden("TutorName", username) will, as Darin Dimitrov explains, render the last POSTed value. Ie, regardless of your loop, ALL the items will be rendered with the TutorName of the last deleted Tutor!

The word around, in Razor syntax is to replace the @Html.Hidden call with an explicit input tag:

<input type="hidden" id="TutorName" name="TutorName" value='@username' />

This works as expected.

Ie:

NEVER, EVER USE Html.Hidden TO PASS A PARAMETER BACK TO YOUR ACTIONS WHEN YOU ARE USING MULTIPLE FORMS IN A GRID!!!

Final Caveat:

When constructing your hidden input tag, you need to include both name and id, set to the same value, otherwise, at the time of writing (Feb 2011) it won't work properly. Certainly not in Google Chrome. All you get is a null parameter returned if you only have an id and no name attribute.

Share:
69,719
komalV
Author by

komalV

MS Stack Web developer based in South Africa.

Updated on April 01, 2020

Comments

  • komalV
    komalV about 4 years

    Something pretty weird is happening with my app:

    I have the following property in my ViewModel:

    public int? StakeholderId { get; set; }
    

    It gets rendered in a partial view as follows:

    <%= Html.Hidden("StakeholderId", Model.StakeholderId) %>
    

    The form is submitted, and the relevant controller action generates an id and updates the model, before returning the same view with the updated model

    The problem I'm experiencing is that the hidden field does not have anything in its "value" attribute rendered the second time even though StakeholderId now has a value.

    If I just output the value on its own, it shows up on the page, so I've got it to render the value by doing this:

    <input type="hidden" id="StakeholderId" name="stakeholderId" value="<%: Model.StakeholderId %>" />
    

    But it's pretty strange that the helper doesn't pick up the updated value?

    (I'm using jQuery to submit forms and render the action results into divs, but I've checked and the html I get back is already wrong before jQuery does anything with it, so I don't think that has much to do with anything)

    UPDATE

    I've since discovered that I can also clear the relevant ModelState key before my controller action returns the partial view.

  • komalV
    komalV over 14 years
    Thanks, that's pretty counter-intuitive though isn't it? If I pass a concrete value in the value parameter, surely I want it to be emitted otherwise I would omit it altogether? I wonder what the reason for this design is...
  • Irwin
    Irwin over 11 years
    Just one thing on the caveat, when submitting form data, the name attribute is what's used to identify the data to the server, not the id.
  • aruno
    aruno over 11 years
    @veli - the reason is to allow you to put a 'default' or 'initial value' but if it didn't redisplay submitted values then you'd lose all the data posted when the page is redisplayed with errors. more specifically it's looking for ModelState values and not POSTed values. if you remove from ModelState then it won't have this behavior
  • pomarc
    pomarc over 7 years
    thanks Darin, could you please post a link to some official doc about that behaviour? thanks
  • Terence Golla
    Terence Golla almost 7 years
    Here is the actual code to put this in your controller when you need the POSTed value in your hidden field will be replaced with the model value set in the controller. ModelState.Remove("StakeholderId");