MVC 4 @HTML.HiddenFor are not updating on a postback
Solution 1
The default HtmlHelpers behavior (@Html.HiddenFor, etc) is to behave exactly as you have described.
i.e. any changes you make to the ViewModel on a post are actioned, any changes you return from the Post are received by the view, but on re-rendering WITH HTMLHELPERS, the previous Post-values take precedence over the changed ViewModel values.
Want to "fix" this behavior in a quick + dirty way, clear the ModelState.Clear() prior to returning from the HttpPost ActionMethod !
Solution 2
As mentioned by joedotnot this is intended behaviour. Another 'quick fix' for this is to code the html for the hidden field and update only the value from the model eg:
<input type="hidden" id="ErrMessage" name="ErrMessage" value="@Model.ErrMessage">
Use the same id
and name
as your model property and the updated value will be rendered after postback.
Solution 3
I've faced similar problem recently and ended up with writing new simple helper method + 2 overloads. I'm sharing it here in case anybody is still looking for some workaround cause this "feature" is sometimes annoying.
public static class CustomExtensions
{
public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
ReplacePropertyState(htmlHelper, expression);
return htmlHelper.HiddenFor(expression);
}
public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
{
ReplacePropertyState(htmlHelper, expression);
return htmlHelper.HiddenFor(expression, htmlAttributes);
}
public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
{
ReplacePropertyState(htmlHelper, expression);
return htmlHelper.HiddenFor(expression, htmlAttributes);
}
private static void ReplacePropertyState<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
string text = ExpressionHelper.GetExpressionText(expression);
string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(text);
ModelStateDictionary modelState = htmlHelper.ViewContext.ViewData.ModelState;
if (modelState.ContainsKey(fullName))
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
ValueProviderResult currentValue = modelState[fullName].Value;
modelState[fullName].Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), currentValue.Culture);
}
}
}
Then you just use it as usual from within you view:
@Html.HiddenFor2(m => m.Id)
It worth to mention it works with collections too.
Solution 4
I think you should be using them like this instead:
@Html.HiddenFor(x => x.Err)
@Html.HiddenFor(x => x.ErrField)
@Html.HiddenFor(x => x.ErrMessage)
@Html.HiddenFor(x => x.IsMove)
Without seeing your model, I am assuming it looks something like this:
public class ErroViewModel
{
public string Err { get; set; }
public string ErrField { get; set; }
public string ErrMessage { get; set; }
public bool IsMove { get; set; }
}
If not it should be similar with public properties as above.
Update
In your get do you have the following?
public ActionResult Index(HomePageModel model)
{
var model = new HomePageModel();
return View(model);
}
I would also change your form from this:
<form id="formData" method="post" action="/Home/Index">
To this:
@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
// rest of form
}
Related videos on Youtube
user799301
Updated on July 09, 2022Comments
-
user799301 almost 2 years
Having issues with the view state on a series of page views -- On the initial view of a page in Razor I am using
Html.HiddenFor
as follows:@Html.HiddenFor(x => Model.err) @Html.HiddenFor(x => Model.errField) @Html.HiddenFor(x => Model.errMessage) @Html.HiddenFor(x => Model.IsMove)
which seems to work fine. My hidden input tags contain the correct values. However when I submit the form
[HTTPPost]
and update the model in my controller action with..model.err = transHelper.err; model.errField = transHelper.errField; model.errMessage = transHelper.errMessage; return View(model);
The hidden fields do not seem to update, they contain the original values from the initial view. However When I use these fields in another context within the same razor view like this...
@* this seems to not update correctly... @Html.HiddenFor(x => Model.err) @Html.HiddenFor(x => Model.errField) @Html.HiddenFor(x => Model.errMessage) @Html.HiddenFor(x => Model.IsMove) *@ <input type="hidden" id="err" value="@Model.err" /> <input type="hidden" id="errField" value="@Model.errField" /> <input type="hidden" id="errMessage" value="@Model.errMessage" /> <input type="hidden" id="IsMove" value="@Model.IsMove" /> </div>
Then the input fields update correctly. I even created a View Helper to help debug, and in all cases, the Model seems to have correct data in
HtmlHelper<TModel>
-- I even returned the Model asreturn Json(model);
and the data was fine.At this point I am running with the work around, but does anybody know why
@Html.HiddenFor
is dirty.Update: here is my controller actions
[HttpPost] public ActionResult Index(HomePageModel model) { // process transaction Transactionr transr = new Transactionr(); transr.Process(model); model.err = transr.err; model.errField = transr.errField; model.errMessage = transr.errMessage; return View(model); }
Here is my view:
@model App.Models.HomePageModel @{ ViewBag.Title = "Product Categorizer"; } <form id="formData" method="post" action="/Home/Index"> @Html.AntiForgeryToken() <fieldset> <div> @Html.HiddenFor(model => model.err) @Html.HiddenFor(model => model.errField) @Html.HiddenFor(model => model.errMessage) @Html.HiddenFor(model => model.IsMove) <input type="hidden" id="myerr" value="@Model.err" /> <input type="hidden" id="myerrField" value="@Model.errField" /> </div> <div class="section group"> <div class="col span_2_of_2"> <div class="message" id ="message"> @if (Model.err < 0) { <span style="color: purple;">@Model.errMessage (@Model.err) - (@Model.errField)</span> } else if (Model.err > 0) { <span style="color:red;">@Model.errMessage (@Model.err) (@Model.errField)</span> } else { <span>@Model.errMessage (@Model.err) (@Model.errField)</span> } </div> </div> </div> <div class="section group" id="workspace"> @Html.Partial("_WorkspacePartial", Model) </div> <div class="section group" id="details"> @Html.Partial("_DetailPartial", Model) </div> </fieldset> </form>
Here is my model:
public class HomePageModel { public int FromStore { get; set; } // the "To" part of the copy/move transaction public int ToStore { get; set; } // a list of the copy/move transaction public List<int> Details { get; set; } // true is move false is copy public bool IsMove { get; set; } // current message public int err { get; set; } public int errField { get; set; } public string errMessage { get; set; }
-
user799301 over 10 yearsMy Model is using public properties. In terms of the expression, I've tried everything including what you suggest, and it doesn't seem to have any impact.
-
user799301 over 10 yearsYes, in my get am creating an instance of HomePageModel.. as for the form.. I am doing some form manipulation with jquery so I've coded it like that.
-
hutchonoid over 10 yearsHmmm, not sure what the problem could be as it all looks good for me. Still an issue?
-
Mat J about 10 yearsIts the
ModelState
that is causing it. See the other answer. -
321X almost 8 yearsThis is very dirty because all the Validation messages are cleared then as well, so be aware!
-
agrath over 7 yearsI thought I was going crazy.
-
Marc Roussel over 6 yearsI don't get it. There's no Required attribute on any properties of the model. Why returning the view was getting the HiddenFor empty for ONE property ? After doing the ModelState.Clear I was getting the value all right !!!
-
Kiquenet over 5 yearsWHY _ clear the ModelState.Clear() prior to returning from the HttpPost ActionMethod_ ?
-
Kiquenet over 5 yearsWhy not use
[HttpPost]
attribute ? -
hutchonoid over 5 years@Kiquenet I would yes, it was just missing from the answer.
-
Rob10e almost 5 yearsThis worked like a charm, thanks!
-
Nick over 4 yearsOdd behavior (still persists in Razor Pages). It seems to occur because
By default, the validation system treats non-nullable parameters or properties as if they had a [Required] attribute.
according to the docs (docs.microsoft.com/en-us/aspnet/core/mvc/models/…), but even a singlestring
type (nullable) model property used as hidden-input (viaasp-for
) is affected by this behavior, and its value is silently reverted to the previous value. -
KyleMit almost 4 yearsThis looks like it was already covered it maxscan's answer posted two years earlier