2

I have a form that uses a modelview object that is not updating a textbox value on postback of submitting a form. On submitting a form, I edit the property of an object that is binded to a textbox. When the form comes back, the object property is still changed, but the textbox value does not change. It's like the textbox value is cached and will not change. How do I fix this?

Textbox default value: ""

Textbox code:

@Html.TextBoxFor(m => m.Project.tNumber, new { @readonly = "readonly", @class = "readonly" })

Object property:

[Display(Name = "T Number")]
[DisplayFormat(ConvertEmptyStringToNull = false)]
public string tNumber { get; set; }

Controller Action Method:

[Authorize(Roles = "Admin, OrderEntryManager")]
[HttpPost]
public ActionResult Verify(string submit, OrderEntryEdit model)
{
    MembershipUser user = Membership.GetUser(User.Identity.Name);
    int userId = WebSecurity.GetUserId(User.Identity.Name);
    if (userId > 0)
    {
        if (ModelState.IsValid)
        {
            string ButtCommand = submit;
            switch (ButtCommand)
            {
                case "Create Order":
                if (model.CreateOrder(userId))
                {
                    ViewBag.Status = "success";
                    ViewBag.Message = "The order has been created.";
                }
                else
                {
                    ViewBag.Status = "error";
                    ViewBag.Message = "There was a problem in trying to create this order.";
                }
                default:
                    ViewBag.Status = "error";
                    ViewBag.Message = "Unrecognized form action.";
            }
        }
    }
    else
    {
        ViewBag.Status = "error";
        ViewBag.Message = "Unrecognized user.";
    }
    return View("Verify", model);
}

ViewModel method:

public class OrderEntryEdit : OrderEntry
{
    public OrderEntryEdit()
    {
        base.Project = new Project();
        base.ShipTo = new ShipTo();
        base.SoldTo = new SoldTo();
        base.Unit = new List<Unit>();
    }
    //method simplified, but is reaching this method
    public Boolean CreateOrder(int adminUserId = 0)
    {
        this.Project.tNumber = "T123456";
        return true;
    }
}

Textbox value: ""

Edit: replacing the code for textbox with this:

<input type="text" readonly="readonly" class="readonly" value="@Model.Project.tNumber" />

has fixed the problem. Apparently, the textbox is being cached. In short, don't use razor syntax, good old html works fine. I hope this helps someone else!

Jakal
  • 62
  • 2
  • 13
  • What is your Controller action signature? Fiddler is your best friend when troubleshooting these, it almost is always to do with naming – reckface Sep 26 '14 at 14:50
  • And you've said the textbox is readonly!?! – reckface Sep 26 '14 at 14:50
  • Did you push the changed viewmodel back into the view? i.e. in response, you need to do `return View("ViewName", model)` instead of just `return View("ViewName")` – tweray Sep 26 '14 at 14:55
  • Ok, checking the object properties in fiddler on postback shows the tNumber value is empty, but the conditionals on the view are being triggered as if the value is not empty. – Jakal Sep 26 '14 at 15:09
  • Please edit your question and post the full post action method. – Chris Pratt Sep 26 '14 at 15:25
  • What's the value of `submit` parameter when you post the form? Is it `"Create Order"` ? – ekad Sep 26 '14 at 15:51
  • Ok, I added the viewmodel method in the question that modifies the object property. I can see that the object property has the new value when it returns from the CreateOrder() method in the controller using the Visual Studio debugger. It doesn't show up in fiddler on postback. Almost like the object being returned is a cached object. Also, yes, the submit parameter value is "Create Order". – Jakal Sep 26 '14 at 15:55
  • Can you try to remove the `readonly` attribute and see if the value changes after postback? – ekad Sep 26 '14 at 15:59
  • Ok, I removed the readonly attribute and class for the textbox, but the tNumber property is still returning an empty value according to fiddler. – Jakal Sep 26 '14 at 16:04
  • Ok, I replaced the textbox with this: and it works fine now. WTH. – Jakal Sep 26 '14 at 16:25

1 Answers1

8

The editors like TextBoxFor, DropDownListFor, etc. use the ModelState values instead of the values from the model you passed to the view. The ModelState contains the values that the user submitted with the form.

You can clear out the entire ModelState by calling ModelState.Clear() in your action. Then the editors will use the values from your model instead.

This is a bit counterintuitive. The explanation on this thread finally made sense to me.

The reason we use the posted value for editors rather than the model value is that the model may not be able to contain the value that the user typed. Imagine in your "int" editor the user had typed "dog". You want to display an error message which says "dog is not valid", and leave "dog" in the editor field. However, your model is an int: there's no way it can store "dog". So we keep the old value.

Britton
  • 2,965
  • 2
  • 22
  • 24