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

C#.Netasp.net MvcHtml Helper

C# Problem Overview


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.

C# Solutions


Solution 1 - C#

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 - C#

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVeli GebrevView Question on Stackoverflow
Solution 1 - C#Darin DimitrovView Answer on Stackoverflow
Solution 2 - C#awrigleyView Answer on Stackoverflow