Kevin Toruño
Kevin Toruño

Reputation: 1

What am I missing? value passed from 'Save' Action is always Null - MVC

In my view MoviesForm.cshtml there is a BeginForm which I am trying to use to pass a model to an action called Save in the Movies controller. However, when debugging, I noticed that this model passed to the Save action is always null and I am just not sure why.

Here is the model class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace vidly.Models
{
    public class Movies
    {
        public Movies() 
        {
            DateAdded = DateTime.Now;
        }

        public int Id { get; set; }
        public string Name { get; set; }

        [Display(Name = "Number in Stock")]
        public int Availability { get; set; }

        [Display(Name = "Release Date")]
        public DateTime ReleaseDate { get; set; }

        public DateTime DateAdded { get; set; }

        public Genre Genre { get; set; }

        [Display(Name = "Genre")]
        [Required]
        public int GenreId { get; set; }
    }
}

Here is my action in the controller

[HttpPost]
public ActionResult Save(Movies movies)
{
        System.Diagnostics.Debug.WriteLine($"Object: {movies.Name} {movies.Id}");

        if (movies.Id == 0)
        {
            movies.DateAdded = DateTime.Now;
            _context.Movies.Add(movies);
        }
        else 
        {
            var selectedMovie = _context.Movies.Single(c => c.Id == movies.Id);
            selectedMovie.Name = movies.Name;
            selectedMovie.ReleaseDate = movies.ReleaseDate;
            selectedMovie.GenreId = movies.GenreId;
            selectedMovie.Availability = movies.Availability;             
        }

        _context.SaveChanges();

        return RedirectToAction("Index", "Movies");
}

And here is the view

@model vidly.ViewModel.MoviesFormViewModel
@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>@ViewBag.Save - Movie</h2>

@using (Html.BeginForm("Save", "Movies"))
{
    <div class="form-group">
        @Html.LabelFor(m => m.Movie.Name)
        @Html.TextBoxFor(m => m.Movie.Name, new { @class = "form-control" })
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Movie.ReleaseDate)
        @Html.TextBoxFor(m => m.Movie.ReleaseDate, "{0:d MMM yyyy}", new { @class = "form-control" })
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Movie.GenreId)
        @Html.DropDownListFor(m => m.Movie.GenreId, new SelectList(Model.Genre, "Id", "Name"), "Select a Genre", new { @class = "form-control" })
    </div>
    <div class="form-group">
        @Html.LabelFor(m => m.Movie.Availability)
        @Html.TextBoxFor(m => m.Movie.Availability, new { @class = "form-control" })
    </div>
    @Html.HiddenFor(m => m.Movie.Id)
    <button type="submit" class="btn btn-primary">Save</button>
}

Thanks!

Upvotes: 0

Views: 232

Answers (2)

Kevin Toru&#241;o
Kevin Toru&#241;o

Reputation: 1

Thank you!! It worked, I changed the parameter from the Save action to MovieFormViewModel, I actually though about doing something like that, but I got another controller which works exactly the same way as I was previously trying, so I didn't do it.

Upvotes: 0

Jonesopolis
Jonesopolis

Reputation: 25370

Your ViewModel is a MoviesFormViewModel. When you use the extensions to build things like @Html.TextBoxFor(m => m.Movie.Name, the generated html (which you should take a look at) is going to expect an object that has a Movie object as a property on it.

But your controller is expecting a Movies object directly. So the framework's ModeBinder is going to get hung up on building your model and trying to figure out how to map the properties, because they are not the same object.

You can change the controller action to accept a MoviesFormViewModel, then access the Movie property on that, or you can manually build your inputs to match the Movies object the action is expecting.

Upvotes: 2

Related Questions