0

I'm running into a problem with the ModelState already having errors when getting a PartialView using @Html.Action().

I have the following controller:

using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;

public class TestController : Controller
{
    private readonly object[] items = {new {Id = 1, Key = "Olives"}, new {Id = 2, Key = "Tomatoes"}};

    [HttpGet]
    public ActionResult Add()
    {
        var model = new ViewModel {List = new SelectList(items, "Id", "Key")};
        return View(model);
    }

    public ActionResult _AddForm(ViewModel viewModel)
    {
        var errors = ModelState.Where(m => m.Value.Errors.Count > 0).ToArray();
        return PartialView(viewModel);
    }
}

And the following ViewModel:

public class ViewModel
{
    [Required]
    public int? SelectedValue { get; set; }
    public SelectList List { get; set; }
}

The Add view looks like this:

@model ViewModel
<h1>Add a thing to a list</h1>
@using (Html.BeginForm())
{
    @Html.ValidationSummary()
    @Html.Action("_AddForm", Model)
    <button class="btn btn-success">Submit</button>
}

Finally the _AddForm PartialView looks like this:

@model ViewModel
<div class="form-group">
    @Html.ValidationMessageFor(m => m.SelectedValue)
    @Html.LabelFor(m => m.SelectedValue, "Please select a thing:")
    @Html.DropDownListFor(m => m.SelectedValue, Model.List, new {@class = "form-control"})
</div>

When this page loads the ModelState already has an error in the PartialView because the SelectedValue is required.

I don't understand why this happens, surely the _AddForm action is a HTTP GET and does not cause model state validation?

(Note, I don't want to use @Html.Partial() because I need to do some logic in the Action.)

Underscore
  • 1,017
  • 2
  • 10
  • 26
  • First of all, follow the naming conventions. A method name should start with a capital letter. `_AddForm` is not a good name for a method. Why do you even have `viewModel` as a parameter in your child action? That doesn't make any sense. – ataravati Jun 20 '15 at 14:52
  • Just remove the `ViewModel viewModel` parameter from the `_AddForm()` method and initialize a new instance (as you do in the `Add()` method). The first step in the model binding process is that a new instance of your model is initialized, and because `SelectedValue` is `null` (the default for nullable int) and because it has the `[Required]` attribute, an error is added to `ModelState` so therefore will be displayed in the view. Alternatively, set the value of `SelectedValue` in the `Add()` method. –  Jun 21 '15 at 00:45

1 Answers1

0

The reason this occurs is that passing the strongly typed ViewModel as a parameter to the action causes the model binding and validation to occur again.

There seems to be no way to avoid this re-validation.

I originally attempted to use the Action as a way to get around the way MVC seemed to be caching some information about my ViewModel when using Html.Partial().

This "caching" turned out to be in the ModelState: https://stackoverflow.com/a/7449628/1775471

Community
  • 1
  • 1
Underscore
  • 1,017
  • 2
  • 10
  • 26