Jarrich Van de Voorde
Jarrich Van de Voorde

Reputation: 396

ViewModel properties stay null on HttpPost

I'm completely puzzled how this simple concept doesn't seem to work. I have a ViewModel, a Controller and a View...

This is my basic ViewModel

public class CreateProfessionalEducationViewModel
{

    public Models.ProfessionalEducation ProfessionalEducation;

    public int ConsultantId;

    public CreateProfessionalEducationViewModel() {} // parameterless constr

}

These are my 2 controller methods

 public ActionResult Create(int id)
    {
        var viewModel = new CreateProfessionalEducationViewModel
        {
            ConsultantId = id
        };

        return View(viewModel);
    }

    //
    // POST: /ProfessionalEducation/Create

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(CreateProfessionalEducationViewModel collection)
    {
        if (ModelState.IsValid)
        {
            //db.ProfessionalEducations.Add(professionaleducation);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View();
    }

and my view...

@model Axxes_Virtual_Resume_MVC.ViewModel.ProfessionalEducation.CreateProfessionalEducationViewModel
@using (Html.BeginForm("Create", "ProfessionalEducation")) {
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)

<fieldset>
    <legend>ProfessionalEducation</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.ProfessionalEducation.Year)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.ProfessionalEducation.Year)
        @Html.ValidationMessageFor(model => model.ProfessionalEducation.Year)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.ProfessionalEducation.Title)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.ProfessionalEducation.Title)
        @Html.ValidationMessageFor(model => model.ProfessionalEducation.Title)
    </div>
    @Html.HiddenFor(model => model.ConsultantId)
    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>
}

For some weird reason my ConsultantId is 0 and ProfessionalEducation is null in my ViewModel when posted back to the HttpPost Create method in my controller.

This should be so basic, what am I forgetting?

Thanks in advance!!

Upvotes: 2

Views: 1491

Answers (3)

Jarrich Van de Voorde
Jarrich Van de Voorde

Reputation: 396

Using properties instead of fields in my ViewModel fixed it for me.

Thanks to anyone for their effort.

Upvotes: 1

Flavia Obreja
Flavia Obreja

Reputation: 1237

The name attribute of the tags must be "ProfessionalEducation.Year" or "ProfessionalEducation.Title" in order that the default binding to work. So use this:

@Html.TextBox("ProfessionalEducation.Year")

instead of

@Html.EditorFor(model => model.ProfessionalEducation.Year)

and the same for Title property. You can read more about ASP.NET MVC Model Binding in this useful post: http://dotnetslackers.com/articles/aspnet/Understanding-ASP-NET-MVC-Model-Binding.aspx

Upvotes: 0

Simon Rapilly
Simon Rapilly

Reputation: 393

The main problem is that, the loony that is the DefaultModelBinder (what reconstruct viewmodels from an HttpFormCollection) works on properties not variables.

And if I'm not mistaken, I do believe the default model binder don't work so well if you use inner objects like that in your Viewmodel and access their properties directly in the View.

Try something like that :

public class CreateProfessionalEducationViewModel
{
    public int ConsultantId  { get; set; }

    public int ProfessionalEducationYear { get; set; }

    public string ProfessionalEducationTitle  { get; set; }
}

And for the view of course

@model Axxes_Virtual_Resume_MVC.ViewModel.ProfessionalEducation.CreateProfessionalEducationViewModel
@using (Html.BeginForm("Create", "ProfessionalEducation")) {
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)

<fieldset>
    <legend>ProfessionalEducation</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.ProfessionalEducationYear )
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.ProfessionalEducationYear )
        @Html.ValidationMessageFor(model => model.ProfessionalEducationYear )
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.ProfessionalEducationTitle)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.ProfessionalEducationTitle)
        @Html.ValidationMessageFor(model => model.ProfessionalEducationTitle)
    </div>
    @Html.HiddenFor(model => model.ConsultantId)
    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>
}

As a rule try to avoid referencing Model objects in your ViewModels (but that's just a design rule)

Upvotes: 1

Related Questions