Miraziz
Miraziz

Reputation: 509

Cannot get selected value from SelectList Razor Pages

I'm making a simple MovieApp using Razor Pages. I have two models: Movie * - 1 Genre. What I want is that when I navigate to Genres page and select a particular Genre, I want to show List of all the movies associated with this Genre, and I would like to be able to select and Navigate to the Movie from Genre.

The problem that I have is that the Razor Pages' SelectList is not Binding selected reference value (i.e objects of Movies) from the list, but when I have IDs of Movies instead, I'm getting the selected value correctly.

Here is my code:

Details.cshtml

<div>
<h4>Genre</h4>
<hr />
<form method="post">
    <dl class="row">
        <dt class="col-sm-2">
            @Html.DisplayNameFor(model => model.Genre.GenreTitle)
        </dt>
        <dd class="col-sm-10">
            @Html.DisplayFor(model => model.Genre.GenreTitle)
        </dd>
    </dl>
    <div class="form-group" style="width: 250px;">
        <label asp-for="MoviesSL" class="control-label"></label>
        <select asp-for="SelectedMovie" class="form-control"
                asp-items="Model.MoviesSL">
        </select>
    </div>
    <span asp-validation-for="SelectedMovie.ID" class="text-danger"></span>
    <div>
        <input type="submit" value="Navigate" class="btn btn-info" />
    </div>
</form>

Details.cshtml.cs

    public Genre Genre { get; set; }
    [Display(Name = "Movies list")]
    public SelectList MoviesSL { get; set; }
    private Movie selectedMovie;
    [BindProperty]
    public Movie SelectedMovie 
    {
        get => selectedMovie;
        set
        {
            selectedMovie = value;
            //int g = 0;
        }
    }

    public async Task<IActionResult> OnGetAsync(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }

        Genre = await _context.Genre.Include(m => m.Movies).FirstOrDefaultAsync(m => m.GenreId == id);
        MoviesSL = new SelectList(Genre.Movies);

        //int g = 0;

        if (Genre == null)
        {
            return NotFound();
        }
        return Page();
    }

    public void OnPost()
    {
        var k = SelectedMovie;

        //int g = 0;
    }

Movie.cs

public class Movie
    {
        [Key]
        public int ID { get; set; }

        [Required]
        [StringLength(60, MinimumLength = 3)]
        public string Title { get; set; }

        [DataType(DataType.Date)]
        [Display(Name = "Release Date")]
        [DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
        public DateTime ReleaseDate { get; set; }

        [Range(1, 300)]
        [DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18,2)")]
        public decimal Price { get; set; }

        [Required]
        [StringLength(5)]
        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
        public string Rating { get; set; }

        public int GenreId { get; set; }
        public Genre Genre { get; set; }

        public override string ToString()
        {
            return Title;
        }
    }

Genre.cs

public class Genre
{
    public Genre()
    {
        Movies = new List<Movie>();
    }

    [Key]
    public int GenreId { get; set; }
    [Required]
    [StringLength(30, MinimumLength = 5)]
    [Display(Name = "Genre Title")]
    [RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]
    public string GenreTitle { get; set; }

    [Display(Name = "Number of movies")]
    public ICollection<Movie> Movies { get; set; }

    public override string ToString()
    {
        return GenreTitle;
    }
}

When I select a movie from the list and try to "navigate" through the post method I get an empty Movie object.

When I select a movie from the list, I get an empty Movie object

However, when I have SelectList of IDs instead Movies, it works properly:

Working correctly

Upvotes: 0

Views: 2511

Answers (2)

Yiyi You
Yiyi You

Reputation: 18179

Firstly,<select></select> will only return it's selected value,it cannot bind model.And you can use MoviesSL = new SelectList(Genre.Movies,"ID","Title"); as Sergey said.And then you can return the selected ID of Movie to post handler.And then get Movie with ID from _context.

1.remove

<span asp-validation-for="SelectedMovie.ID" class="text-danger"></span>

2.change

[BindProperty]
    public Movie SelectedMovie 
    {
        get => selectedMovie;
        set
        {
            selectedMovie = value;
            //int g = 0;
        }
    }

to

[BindProperty]
        public int SelectedMovie { get; set; }

3.change

public void OnPost()
    {
        var k = SelectedMovie;

        //int g = 0;
    }

to

public void OnPost()
    {
        Movie k = _context.Movie.Where(m=>m.ID== SelectedMovie).FirstOrDefault();

        //int g = 0;
    }

Upvotes: 1

Serge
Serge

Reputation: 43900

To initiate SelectList you need 3 properties: list of items, name of property of the item that can be used a Value for the SelectList, and name that can be used to display SelectList.

So you have to fix SelectList code:

 MoviesSL = new  SelectList(Genre.Movies,"ID","Title");

Upvotes: 1

Related Questions