I came across a bizarre situation where I am incrementing a simple int value on a model and EditorFor was failing to display the updated value. I was working in MVC 2 Preview 2 but downloaded and verified the same behavior in RC2. Before I report this
as a bug, I just wanted to see if there was any reason this should be considered correct behavior.
To Reproduce:
Create a new MCV 2 web application.
Under Models, create the following model:
namespace MvcApplication1.Models
{
public class TestModel
{
public int Value { get; set; }
}
}
Under the Views/Home directory add create a view called Test.aspx containing the following markup:
In the HomeController add the following two methods:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Test(int id)
{
return View(new TestModel { Value = id });
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Test(TestModel model)
{
model.Value++;
return View(model);
}
Finally, run the application and navigate to /Home/Test/1
You should see output like:
Display: 1 Edit: [1 ] [Submit Query]
Hit submit and you will see output like:
Display: 2 Edit: [1 ] [Submit Query]
The model correctly incremented the value and DisplayFor correctly rendered the model. However, EditorFor rendered the old value. I didn't dig into why it did this but, at a guess it seems to be an issue with an out of date value in the ModelMetaData or
similar.
In my effort to work around this issue I added the following hidden inputs to the above view.
<%=Html.Hidden("Value") %> <!-- Renders old value -->
<%=Html.Hidden("Value", Model.Value) %> <!-- Renders old value -->
<%=Html.Hidden("Value", "Not a Number") %> <!-- Renders old value !! -->
<%=Html.Hidden("Test", Model.Value) %> <!-- Renders new value -->
<%=Html.Hidden("Test", "Not a Number")%> <!-- Renders "Not a Number" -->
After running the modified code and clicking submit as described above, I viewed the source of the rendered HTML. As indicated by the comments, Html.Hidden() ignored the second argument passed any time the first argument matched the name of a property on
the model. And like with EditorFor, it would also render the old value in these cases.
The difference between editor and display is that the editor is a textbox, and the textbox is POST-ed .
So, I think that when POST-ed, the editor have the values from POST data(usually you do not change the users values on POST ... but put into the database...), and the display from the model ( because there are no POST-ed fields from where the values should
come from)
The difference between editor and display is that the editor is a textbox, and the textbox is POST-ed .
So, I think that when POST-ed, the editor have the values from POST data(usually you do not change the users values on POST ... but put into the database...), and the display from the model ( because there are no POST-ed fields from where the values should
come from)
This is correct. This behavior is identical to the MVC 1.0 behavior.
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.
If you don't want the old values in the editor, clear out the Model State. That's where the old value is stored and pulled from the HTML helpers.
Marked as answer by ricka6 on Feb 18, 2010 09:01 PM
To make sure I fully understand the implications here, would a good rule of thumb be that the controller should clear the model state once it has confirmed that the state is valid, in order to ensure that updated values get sent back to the browser? The
example I gave was very simple but the intended behavior is that when the user submits data, the changes are integrated with any changes made elsewhere to the record and that these integrated results be displayed.
To make sure I fully understand the implications here, would a good rule of thumb be that the controller should clear the model state once it has confirmed that the state is valid, in order to ensure that updated values get sent back to the browser? The
example I gave was very simple but the intended behavior is that when the user submits data, the changes are integrated with any changes made elsewhere to the record and that these integrated results be displayed.
Yes, clearing the ModelState works.
Personally, I prefer never to render success pages as the result of a POST operation, for caching and history reasons. If you were to Redirect at the end of a successful update operation -- even if you redirected to the exact same URL -- then you would also
solve this problem, and get better caching and history behavior as well.
Marked as answer by ricka6 on Feb 22, 2010 09:35 PM
kbaltrinic
Member
6 Points
21 Posts
A Bug? EditorFor and DisplayFor don't display same value - EditorFor out of date
Feb 18, 2010 02:14 PM|LINK
I came across a bizarre situation where I am incrementing a simple int value on a model and EditorFor was failing to display the updated value. I was working in MVC 2 Preview 2 but downloaded and verified the same behavior in RC2. Before I report this as a bug, I just wanted to see if there was any reason this should be considered correct behavior.
To Reproduce:
Create a new MCV 2 web application.
Under Models, create the following model:
namespace MvcApplication1.Models { public class TestModel { public int Value { get; set; } } }Under the Views/Home directory add create a view called Test.aspx containing the following markup:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcApplication1.Models.TestModel>" %> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <%using(Html.BeginForm("Test", "Home")){%> <h2>Test</h2> Display: <%=Html.DisplayFor(m => m.Value) %> Edit: <%=Html.EditorFor(m => m.Value) %> <input type="submit" /> <%} %> </asp:Content>In the HomeController add the following two methods:
[AcceptVerbs(HttpVerbs.Get)] public ActionResult Test(int id) { return View(new TestModel { Value = id }); } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Test(TestModel model) { model.Value++; return View(model); }Finally, run the application and navigate to /Home/Test/1
You should see output like:
Display: 1 Edit: [1 ] [Submit Query]
Hit submit and you will see output like:
Display: 2 Edit: [1 ] [Submit Query]
The model correctly incremented the value and DisplayFor correctly rendered the model. However, EditorFor rendered the old value. I didn't dig into why it did this but, at a guess it seems to be an issue with an out of date value in the ModelMetaData or similar.
Thoughts?
EditorFor DisplayFor
kbaltrinic
Member
6 Points
21 Posts
The plot thickens...
Feb 18, 2010 06:50 PM|LINK
In my effort to work around this issue I added the following hidden inputs to the above view.
<%=Html.Hidden("Value") %> <!-- Renders old value --> <%=Html.Hidden("Value", Model.Value) %> <!-- Renders old value --> <%=Html.Hidden("Value", "Not a Number") %> <!-- Renders old value !! --> <%=Html.Hidden("Test", Model.Value) %> <!-- Renders new value --> <%=Html.Hidden("Test", "Not a Number")%> <!-- Renders "Not a Number" -->After running the modified code and clicking submit as described above, I viewed the source of the rendered HTML. As indicated by the comments, Html.Hidden() ignored the second argument passed any time the first argument matched the name of a property on the model. And like with EditorFor, it would also render the old value in these cases.
Html.Hidden
ignatandrei
All-Star
135148 Points
21679 Posts
Moderator
MVP
Re: The plot thickens...
Feb 18, 2010 08:52 PM|LINK
<Disclaimer : I should look into source code
>
The difference between editor and display is that the editor is a textbox, and the textbox is POST-ed .
So, I think that when POST-ed, the editor have the values from POST data(usually you do not change the users values on POST ... but put into the database...), and the display from the model ( because there are no POST-ed fields from where the values should come from)
bradwils
Contributor
5779 Points
691 Posts
Microsoft
Re: The plot thickens...
Feb 18, 2010 09:00 PM|LINK
This is correct. This behavior is identical to the MVC 1.0 behavior.
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.
If you don't want the old values in the editor, clear out the Model State. That's where the old value is stored and pulled from the HTML helpers.
ricka6
All-Star
15070 Points
2272 Posts
Microsoft
Moderator
Re: The plot thickens...
Feb 19, 2010 02:18 AM|LINK
Awesome work ignatandrei
Eilon says "The stuff in the EditorFor is using ModelState to shows its values, which takes precedence over ViewData."
kbaltrinic
Member
6 Points
21 Posts
A Bug? EditorFor and DisplayFor don't display same value - EditorFor out of date
Feb 22, 2010 10:47 AM|LINK
To make sure I fully understand the implications here, would a good rule of thumb be that the controller should clear the model state once it has confirmed that the state is valid, in order to ensure that updated values get sent back to the browser? The example I gave was very simple but the intended behavior is that when the user submits data, the changes are integrated with any changes made elsewhere to the record and that these integrated results be displayed.
bradwils
Contributor
5779 Points
691 Posts
Microsoft
Re: A Bug? EditorFor and DisplayFor don't display same value - EditorFor out of date
Feb 22, 2010 02:56 PM|LINK
Yes, clearing the ModelState works.
Personally, I prefer never to render success pages as the result of a POST operation, for caching and history reasons. If you were to Redirect at the end of a successful update operation -- even if you redirected to the exact same URL -- then you would also solve this problem, and get better caching and history behavior as well.