3

I have this two lines in a Razor template:

@Html.Hidden("step", Model.Step)
<p>@Html.Label(Model.Step.ToString())</p>

And they produce two different values:

<input data-val="true"
       data-val-number="The field Step must be a number."
       data-val-required="The Step field is required."
       id="step"
       name="step"
       type="hidden"
       value="0">
    <p>
        <label for="">1
        </label>
    </p>

How is this possible?

Property Step is of a type Int32 and is incremented every POST action.

EDIT:

@model ***.WebUI.Models.OrderViewModel
@{
  ViewBag.Title = "New order";
}
<h2>
  New order</h2>
@using (Html.BeginForm())
{
  @Html.Hidden("step", Model.Step)
  <p>@Html.Label(Model.Step.ToString())</p>
  <div>
    //other inputs
  </div>
}
David
  • 10,458
  • 1
  • 28
  • 40
ZxCvBnM
  • 277
  • 3
  • 14
  • Can we see all of the code in this view? This is a very perplexing issue – mituw16 Mar 25 '15 at 16:20
  • What's the actual value of `Model.Step` when you debug? Also, are there any data-annotations attributes defined on the property? – haim770 Mar 25 '15 at 16:22
  • Breakpoint @ return View(orderViewModel); <- value of Step is 1. – ZxCvBnM Mar 25 '15 at 16:25
  • I quickly put something similar to this in a test MVC project, and was not able to duplicate the different values you are seeing. Both the `hidden` and `label` in my test had the correct value from my view model. Very odd...Is there anything else at all in your view code that could be incrementing the value, or javascript that could be clearing the value? – mituw16 Mar 25 '15 at 16:38
  • So, given it is a '1'. does that mean that you have already attempted to POST the form once and it came back? Or does it start as 1 before any POST? – Tommy Mar 25 '15 at 16:40
  • No it's starts at 0 and is posted one time back.There is no javascript incrementing that value. – ZxCvBnM Mar 25 '15 at 16:43
  • Can you show your POST code? Specifically, upon POST, are you redirecting or just returning the view with the model that was submitted to you? – Tommy Mar 25 '15 at 16:56

1 Answers1

2

You have not shown you POST method, but based on "Property Step is of a type Int32 and is incremented every POST action." I assume it looks something like

public ActionResult Edit(OrderViewModel model)
{
  model.Step = model.Step + 1;
  return View(model);
}

When you post a model, the models values are added to ModelState (along with any ModelState errors) so in the first post, the ModelState value of Step will be 0. Html helpers use ModelState values for binding (if one exists) so when you return the view @Html.Hidden("step", Model.Step) will bind to the value of 0 (not the models value of 1). The reason for this behavior is explained in this answer.

The correct approach is to follow the PRG pattern (redirect to the GET method, passing a parameter indicating the Step value and initialize a new OrderViewModel), however you can make this work by clearing ModelState so that the Html Helper will use the model value.

public ActionResult Edit(OrderViewModel model)
{
  ModelState.Clear(); // clear all model state
  model.Step = model.Step + 1;
  return View();
}

However, use this with caution. ModelState.Clear() removes all errors as well.

Community
  • 1
  • 1