1

In my ASP.NET MVC 3 app I have a page where, after its form is submitted I need to change a value from the form. If I do it in the ViewModel it has no effect, I have to do it use ModelState["Field"].Value.

The thing is that I actually have a lot of work I have to do on the ViewModel when the pages loads AND after the POST. So I have a method which receives the ViewModel and do all that work. But, as I said, after the POST, modifying the ViewModel object is useless. Why is that? The method on the controller is returning View(viewModel);. Shouldn't the view use the ViewModel values?

I'd like to understand why is useless to modify the ViewModel and also know if there is some method in the ModelState which "refresh" the fields values throw a ViewModel object.

Here is my controllers code:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(MyViewModel viewModel)
{
    try
    {
        if (ModelState.IsValid)
            //Do stuff and redirect
    }
    catch(Exception ex)
    {
        //Log and add error to the ModelState
    }

    someMethodWhichDoesALotOfThingsInTheViewModel(viewModel);
    return View(viewModel);
}

I think the rest of the code is unnecessary, if anyone think it would help let me know!

Update

I don't want to lose any errors, not even those of the fields changed in the ViewModel. A good example would be a captcha, if the users makes any error in the form (only with the captcha field or only with any other fields and not with the captcha) I want to show him all his errors and also update the captcha. It makes no sense to render the form with the old captcha value inserted so I want to blank that field.

Update 2

I've opted to put @Value = Model.PropertyInViewModel in the HTML Attributes of each Html.TextBoxFor. But I'd prefer to avoid that nasty work so if someone comes out with any better solution please let me know.

Diego
  • 16,436
  • 26
  • 84
  • 136
  • If your method makes changes to `viewModel`, it's the same object you're passing to your `Index` view. There is nothing wrong with the code you've shown us--it must be somewhere else. – David Fox May 27 '11 at 17:36
  • I believe it's ignoring your changes due to a convention. Html helpers will pull back the attempted value if the same view is shown after a post. Just like it would if you failed validation. Try clearing ModelState Errors. – Jab May 27 '11 at 21:08
  • I updated my question, please check it out. – Diego May 30 '11 at 10:29

3 Answers3

4

The following will work:

ModelState.Remove("MyProperty");
viewModel.MyProperty = "new value";

You need to remove it from the model state because HTML helpers first look in there when binding their value.

Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • @Diego, yes you will loose errors for this particular field only. But that's normal as you have changed its value so the original error message that was related to the initial value that was posted by the user no longer makes sense. – Darin Dimitrov May 30 '11 at 06:04
  • I updated my question, I really don't want to lose any error, even those of the fields changed in the ViewModel. – Diego May 30 '11 at 10:28
  • 2
    @Diego, in this case you will have to write your own textbox helpers as the built-in work the way I described in my answer: they first look in the ModelState for values when binding and after that in the model. So if you need to modify some POSTed values in the controller action you either have to remove them from ModelState or don't use the standard helpers. Don't expect miracles. – Darin Dimitrov May 30 '11 at 13:07
0

If you decide to remove modelstate values to prevent round-tripping take a look at this RemoveFor() extension method I made to remove ModelState errors without magic strings.

Community
  • 1
  • 1
Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689
0

All I could came out with is to add @Value = Model.PropertyInViewModel to each Html.TextBoxFor that is going to be modified in the ViewModel.

Another way, as @Darin Dimitrov said, would be to make my own helpers.

Diego
  • 16,436
  • 26
  • 84
  • 136