MVC4 HTML TextBox not working after changing ViewModel

I have a problem that I just don't understand. I have a very simple model that has a list as a public member. Whenever my controller removes an element from the model during postback, the HTML helpers of TextBoxFor () do not see the changes. These helpers seem to cache something, but I can't put it on it.

Demo / Repro can be found here: http://broken.azurewebsites.net

Repro

  • Go to http://broken.azurewebsites.net
  • Note 4 column values ​​filled with null values
  • Click the "test" button to send the POST to the page where I delete the first item in the list.
  • Note. The "real" values ​​are correct and element 0 is deleted, however, the problem here is that the values ​​are displayed through TextBoxFor (). I cannot understand why this is showing 0 when this element no longer exists.

Models

public class ItemViewModel { public string Description { get; set; } public decimal? Amount { get; set; } } public class TestViewModel { public TestViewModel() { Items = new List<ItemViewModel>(); } public List<ItemViewModel> Items { get; set; } } 

controller

 public class HomeController : Controller { public ActionResult Index() { var model = new TestViewModel(); for (var i = 0; i < 4; i++) { model.Items.Add(new ItemViewModel { Description = i.ToString(), Amount = i }); } return View(model); } [HttpPost] public ActionResult Index(TestViewModel model) { model.Items.RemoveAt(0); return View(model); } } 

View

 @model Demo.Models.TestViewModel @using (Html.BeginForm()) { <table> <thead> <tr><td>Description</td><td>Amount</td><td>Real-Description</td><td>Real-Amount</td></tr> </thead> <tbody> @for (var i = 0; i < Model.Items.Count; i++) { var ii = i; <tr> <td>@Html.TextBoxFor(m => m.Items[ii].Description)</td> <td>@Html.TextBoxFor(m => m.Items[ii].Amount)</td> <td>@Model.Items[ii].Description</td> <td>@Model.Items[ii].Amount</td> </tr> } </tbody> </table> <button>Test</button> } 
+7
source share
1 answer

Modify your index method as shown below for the desired behavior:

  [HttpPost] public ActionResult Index(TestViewModel model) { ModelState.Clear(); model.Items.RemoveAt(0); return View(model); } 

That's why:

TextBoxFor is bound to the post value in ModelState instead of the model value. Therefore, in your application, when you click the Test button, text fields are tied to an existing value and are not updated during postback even after changing model values. For example, if the text fields in the first line show 0, and they will be attached to this value even after feedback, and the base model will have a value of 1. The reason for this behavior is verification. If you expect the int in the text box and the user inputs "SomeTextValue", the model’s middleware will not be able to bind to the int property, and it will be in a validation error state. Then you want the user to see an error that says "SomeTextValue" is not an integer. Enter an integer because you expect the value entered by the user to be there.

Rick Strall perfectly explains this in this blog post

http://www.west-wind.com/weblog/posts/2012/Apr/20/ASPNET-MVC-Postbacks-and-HtmlHelper-Controls-ignoring-Model-Changes

And Brand Wilson below:

http://forums.asp.net/post/3688022.aspx

+15
source

All Articles