TextBoxFor displaying initial value, not the value updated from code [duplicate]
I have an MVC application that displays a value. This is the controller:
public ActionResult Index(DataSites DataSiteList)
{
if (DataSiteList.Latitude != null)
{
DataSites test = new DataSites();
test.Latitude = "LATITUDE";
return View(test);
}
return View(DataSiteList);
}
public ActionResult SomeInformation()
{
DataSites test1 = new DataSites();
test1.Latitude = "LATITUDE2";
return RedirectToAction("Index", test1);
}
The View:
@model miniproj2.Models.DataSites
<p>
@Html.TextBoxFor(x => x.Latitude)
</p>
And the Model:
public class DataSites
{
public string Latitude { get; set; }
}
When I go to /Home/SomeInformation, the DataSites
' Latitude
property is set to "LATITUDE2". Then redirects to the Index()
action in the controler, sets the property to "LATITUDE" and returns the view.
When it shows the view, it displays the value "LATITUDE2" as set in the redirect. Shouldn't "LATITUDE" be displayed?
Your problem is (step by step)
- Your
SomeInformation()
method sets the value oftest1.Latitude
to "LATITUDE2". - You then pass that model to your
Index()
method using the overload ofRedirectToAction
that accepts an object. Internally this uses reflection to build aRouteValueDictionary
based on the properties of your model (in this case its simplylatitude="LATITUDE2"
). - When you hit the
Index
method the model is bound by theDefaultModelBinder
and now the value ofDataSiteList.Latitude
is "LATITUDE2" (which is why you enter theif
block) - In the process of binding, the
DefaultModelBinder
sets theModelState
value ofLatitude
to "LATITUDE2". Any attempts to set the value ofLatitude
are now ignored because the view usesModelState
value to render the control.
It not clear what your trying to do here. You can make it work as you expect by adding ModelState.Clear();
as the first line of your Index()
method. This clears all existing ModelState
values an you can now set the value to "LATITUDE".
But your if
block makes no sense. Perhaps you were just doing some kind of test, but you may as well remove the parameter from the Index()
method and just initialize a new instance of DataSites
in the method.
Edit
To give a bit more information as to why updating a model property has no affect once ModelState
has been set.
Imagine you have a form to collect user information where the model contains int Age
. The user is asked to enter their age and someone enters "I'm five next week!". Of course this wont bind to an int so the DefaultModelBinder
adds the value (the attemptedValue
) and adds a ModelStateError
.
When the view is returned it will typically display an error message such as "The field Age must be a number". If the html helper rendering the control used the model value, then it would display "0" (the default value for int). It would be somewhat confusing for the user to see "0" in the textbox and next it a message saying it must be a number (What! but zero is a number and what the heck happened to what I entered?). So instead, the helper uses the value from ModelState
and now the users sees "I'm five next week!" and an associated error message that makes sense for the value.
So even though you thoughts were that "its not logical", there is actually some logic to this behavior.