Kevin Suppan
Kevin Suppan

Reputation: 232

Model not passed in ASP.NET MVC 3

I have an Index View, where I got a form containing a partial view for the different formulars.

@Html.ValidationSummary(true, "Beheben Sie die Fehler, und wiederholen Sie den Vorgang.")
@using (Html.BeginForm())
{
object mod = null;
switch (Model.Step)
{
    case 1:
        Html.RenderPartial("Step1", Model.Step1);
        break;
    case 2:
        Html.RenderPartial("Step2", Model.Step2);
        break;
    default:
        Html.RenderPartial("Step0");
        break;
}

<p>
    @if (Model.Step > 100000)
    {
        <button name="button" value="Zurück" />
    }
    @if (Model.Step != 0)
    {      
        <input type="submit" name="submit" value="Zurück" />   <input type="submit" name="submit"
            value="Weiter" id="Weiter" /> <input type="submit" name="submit" value="Abbrechen" />
    }
</p>
}

In my Controller I got something like this:

[HttpPost]
public ActionResult Index(InputModel model, string submit, HttpPostedFileBase file)
{
    if (String.IsNullOrEmpty(submit))
        submit = "";
    if (submit == "Weiter")
        model.Step++;

    if (submit == "Zurück")
        model.Step--;

The InputModel has several "sub-models" like this:

public Step1Model Step1 { get; set; }

public Step2Model Step2 { get; set; }

public Step3Model Step3 { get; set; }

Which are passed to the partial view to fill them. The problem now is that I always get an empty model in my HttpPost in my controller. What am I doing wrong?

Upvotes: 4

Views: 658

Answers (1)

Darin Dimitrov
Darin Dimitrov

Reputation: 1038710

What am I doing wrong?

You are using partials. Partials don't respect the navigational context. So when you look at your generated HTML source you will see the following:

<input type="text" name="SomeProperty" value="some value" />

instead of the correct one which is expected by the default model binder:

<input type="text" name="Step1.SomeProperty" value="some value" />

So when you submit this form you are not properly binding to the Step1 property. Same remark obviously for the other complex properties.

One possibility is to use editor templates instead of partials because they preserve the navigational context and generate proper names for your input fields.

So instead of:

Html.RenderPartial("Step1", Model.Step1);

use:

@Html.EditorFor(x => x.Step1, "Step1")

and then move your ~/Views/SomeController/Step1.cshtml partial to ~/Views/SomeController/EditorTemlpates/Step1.cshtml.

If you don't want to use editor templates but keep with the partials you could change the temlpate prefix inside the partial. So for example inside Step1.cshtml partial you could put the following in the top:

@{
    ViewData.TemplateInfo.HtmlFieldPrefix = "Step1";
}

Now when you inspect your generated HTML source proper names should be emitted for the input fields. Personally I would recommend you the editor templates approach though to avoid hardcoding the prefix and making this partial less reusable compared to the editor templates.

Upvotes: 7

Related Questions