MVC2 TextBoxFor value not updating after submit?
This is a really strange behavior, and I've set up some demo code to try to figure out what's going on.
Basically have a a two actions and a single view. The first action sends an empty model to the view, the section action recieves the model, alters its contents and sends it back to the same view.
The wierdness is, in the view, the Model seems to have the updated values in it, but when I do an Html.TextBoxFor(x => x.PropertyNameHere) it renders a textbox with the unaltered value in it.
lol... I apologize in advance for the toilet humor, but it keeps the day from getting too boring. ;)
Does anyone have any idea what's going on here? Why is the output of TextBoxFor putting the old value in the value attribute?
Here's the code to replicate:
/Views/Demo/Index.aspx
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<TestWeb.DemoModel>" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Demo</title>
</head>
<body>
<div>
<%using (Html.BeginForm("DemoSubmit", "Admin", FormMethod.Post)) { %>
Foo: <%=Html.TextBoxFor(x => x.Foo)%> <%:Model.Foo %><br />
Bar: <%=Html.TextBoxFor(x => x.Bar) %> <%:Model.Bar %><br />
PoopSmith: <%=Html.TextBoxFor(x => x.PoopSmith) %> <%:Model.PoopSmith %><br />
<button type="submit">Submit</button>
<%} %>
</div>
</body>
</html>
DemoModel.cs
namespace TestWeb {
public class DemoModel {
public string Foo { get; set; }
public int Bar { get; set; }
public string PoopSmith { get; set; }
}
}
DemoController.cs
public class AdminController : Controller {
public ActionResult Index() {
var m = new DemoModel();
return View(m);
}
public ActionResult DemoSubmit(DemoModel demo) {
demo.Foo += "!!!";
demo.Bar++;
demo.PoopSmith += " has pooped.";
return View("开发者_Go百科Index", demo);
}
}
And here's the bizarre output:
Default Html helper try to redisplay the data that is posted to them. They first use the value from posted data and if no posted data is available they take the data from the Model.
This is not what you want obviously, but still the most common usage: You display some data in formfields after receiving a get request. You post to an Update action. If you have errors you want to redisplay the form with the values you entered still available.
I have seen some people getting around this (I think by writing to ModelState), but my choice was always to not use the default helpers if they dont help me. Thats especially true for hidden fields: Most people get confused when they set a value to a hidden field but the value that is realy used is from the post. At least there is a question every other day about it on SO :-)
Forget the "Most people" and replace it with "Everybody".
ASP.NET MVC: Hidden field value does not get rendered using HtmlHelper.Hidden
http://blog.johnwest.com/post/ASPNET-MVC-Hidden-Form-Field-Bug.aspx
http://blogs.msdn.com/b/simonince/archive/2010/05/05/asp-net-mvc-s-html-helpers-render-the-wrong-value.aspx?utm_medium=Twitter&utm_source=Shared
UPDATE Oh I found another one from today (You are not alone):
How to update textbox value
Do ModelState.Clear(); in your controller to prevent this happening. Check MSDN for that.
I'd avoid ModelState.Clear() or ModelState.Remove() unless you absolutely have to. Generally if you see this behaviour it is because a) you're not following the Post-Redirect-Get pattern and should be, or b) if that isn't appropriate you should consider not using the HtmlHelper's TextBox method, as it is mainly designed to help with validation etc when following a PRG pattern.
I'm sure there are exceptions (for example a Wizard-style UI can end up a bit like this), but I'd take that as the default approach.
The solution is to use either ModelState.Remove("[Mode's Property Name]") before it is assigned new value with the Controller. Or on the view page, change Html.TextBoxFor() to Html.TextBox() for the particular model property.
I got the same problem with VS 2010 and I found I hit the wall the whole day. After I thought about the whole night, I think I found the reason. The reason is the persistence. It only remembers whatever value entered on the browser. However, I think this violates the binding principle. If I am allowed to pass a model parameter to the view, the view should bind that parameter by taking whatever I pass in the model's current state.
精彩评论