Daniel Olsen
Daniel Olsen

Reputation: 1050

MVC4: ViewModel is empty on [HttpPost]

I'm trying to make a simple news system in MVC4. I'm very new at it, and I have a simple News base class that looks like this:

NewsPost:

public class NewsPost
{
    public virtual int Id { get; set; }
    public virtual string Subject { get; set; }
    public virtual string Content { get; set; }
}

It's then attached to a category class like so:

NewsCategory:

public class NewsCategory
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<NewsPost> NewsPosts { get; set; }
}

I then have a controller for creating these NewsPosts:

NewsController:

private readonly INewMvcSiteDataSource _db;

public NewsController(INewMvcSiteDataSource db)
{
    _db = db;
}

[HttpGet]
public ActionResult Create()
{
    var model = new CreateNewsViewModel();

    model.Categories = new SelectList(_db.NewsCategories, "Id", "Name");

    return View(model);
}

[HttpPost]
public ActionResult Create(CreateNewsViewModel newsModel)
{
    if (ModelState.IsValid)
    {
        int id = int.Parse(newsModel.SelectedCategories.Single(f => f.Selected).Value);
    }
    return View(newsModel);
}

And lastly, to facilitate with creating the NewsPost, I use a CreateNewsViewModel, like so:

CreateNewsViewModel:

public class CreateNewsViewModel
{
    [Required]
    public string Subject { get; set; }

    [Required]
    public string Content { get; set; }

    public SelectList Categories { get; set; }
    public SelectList SelectedCategories { get; set; }
}

My view looks like this:

Create.cshtml:

@model NewMvcSite.Models.CreateNewsViewModel

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>CreateNewsViewModel</legend>

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

        <div class="editor-label">
            @Html.LabelFor(model => model.Content)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Content)
            @Html.ValidationMessageFor(model => model.Content)
        </div>
        <div class="editor-label">
            @Html.LabelFor(model => model.Categories)
        </div>
        <div class="editor-field">
            @Html.DropDownListFor(model => model.Categories, Model.SelectedCategories)
        </div>
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

For some reason, my viewmodel isn't returned when I click the submit button to create the newspost, and since there is no parameterless constructor for [HttpPost] Create action, it fails with "No parameterless constructor defined for this object."

I've been trying going through other posts here stating the same problem, but I fail to see the connection between what they are doing and what I am doing. I hope there is someone out there who can help me.

Thank you.

Upvotes: 0

Views: 3567

Answers (3)

Daniel Olsen
Daniel Olsen

Reputation: 1050

I found the solution.

I had to change the ViewModel to this:

public IEnumerable<SelectListItem> Categories { get; set; }
public int SelectedCategoryId { get; set; }

I changed the controller to:

var model = new CreateNewsViewModel
                {
                    Categories = new SelectList(_db.NewsCategories, "Id", "Name")
                };

And changed View to this:

@Html.DropDownListFor(x => x.SelectedCategoryId, Model.Categories)

Upvotes: 0

Grimmy
Grimmy

Reputation: 2061

If you want to select category from drop down list, first of all you should add property to your model to hold Id of selected category. Something like this (property Category):

public class CreateNewsViewModel
    {
        [Required]
        public string Subject { get; set; }

        [Required]
        public string Content { get; set; }

        public SelectList Categories { get; set; }
        public SelectList SelectedCategories { get; set; }
        public int Category { get; set; }
    }

after that, you should change code to filling model.Category to this:

model.Categories = new SelectList(categories, "Id", "Name", model.Category);

and than, in your view, editor for Category should look like this:

    <div class="editor-field">
                @Html.DropDownListFor(m => m.Category, Model.Categories);


 </div>

Upvotes: 1

webdeveloper
webdeveloper

Reputation: 17288

model.Categories = new SelectList(_db.NewsCategories, "Id", "Name");

At this line you fill Categories property

@Html.DropDownListFor(model => model.Categories, Model.SelectedCategories)

Here you trying create select with Categories name and SelectedCategories items

int id = int.Parse(newsModel.SelectedCategories.Single(f => f.Selected).Value);

Here you trying get selected item, BUT on form submit you only sending one number, not list. One of your SelectList must be int

Upvotes: 0

Related Questions