Can't get DropdownListFor to work properly

412 views Asked by At

I've been trying to get DropDownListFor working in ASP.NET MVC using values from another table to link the model to the option selected. Full disclosure, I have very little idea what I'm doing and just working off examples.

Creating the DropDownList as follows:

@Html.DropDownListFor(model => model.GenreId, (SelectList)ViewBag.GenreSelect, new { @class = "form-control" })

GenreId is a column in the model's table.

I get the error:

An exception of type 'System.InvalidOperationException' occurred in System.Web.Mvc.dll but was not handled in user code

Additional information: There is no ViewData item of type 'IEnumerable' that has the key 'GenreId'

ViewBag set like this before going to the view: (Id and name are columns in the Genre table)

private void SetGenreViewBag(int? GenreId= null)
    {
        if (GenreId== null)

            ViewBag.GenreSelect= new SelectList(db.Genres, "Id", "name");

        else

            ViewBag.GenreSelect = new SelectList(db.Genres, "Id", "name", GenreId);

    }

The model has a column for the Id of the genre.

I think my main problem is I don't understand the syntax of the DropDownListFor function, plus there's a dozen different overloads for it so it's hard to decipher. What is the purpose of the first parameter with the lambda? It seems to be taking the value you specify from the select list values, but I don't get how this connects to the model. Haven't found a clear answer online.

I thought I had this working, but something I did made it stop working. I also had it working before that with DropDownList() but I saw that DropDownListFor would be a bit better plus I couldn't get the HTML attributes working properly in DropDownList().

Thank you!

EDIT: Inside controller:

    public ActionResult Create()
    {
        SetGenreViewBag();
        return View();
    }

NOTE: The dropdown list shows all the right items (i.e. genres) but it crashes when I save the form.

// POST: Home/Create
    [HttpPost]
    public ActionResult Create(Song songToCreate)
    {
        try
        {
            db.Songs.Add(songToCreate);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

Song model:

namespace MyModule.Models
{
using System;
using System.Collections.Generic;

public partial class Song
    {
        public int Id { get; set; }
        public string name { get; set; }
        public int genreId { get; set; }
    }
}
1

There are 1 answers

8
ekad On BEST ANSWER

When you have this syntax

@Html.DropDownListFor(model => model.GenreId, (SelectList)ViewBag.GenreSelect, new { @class = "form-control" })

The first parameter indicates which property of the model will be assigned the selected value of the dropdown, which is GenreId in this case. I don't see anything wrong with the way you generate the dropdown, but since you get the error when you save the form, I think the problem is inside the Create method with [HttpPost] attribute below.

[HttpPost]
public ActionResult Create(Song songToCreate)
{
    try
    {
        db.Songs.Add(songToCreate);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

I would guess that an error happens for some reason inside the try block, then the code in the catch block is executed and it returns to the same page but ViewBag.GenreSelect is already gone so you get the There is no ViewData item of type 'IEnumerable' that has the key 'GenreId' error. Try to add SetGenreViewBag() inside the catch block so ViewBag.GenreSelect will be repopulated. Also add (Exception ex) to the catch block to find out the error inside the try block

[HttpPost]
public ActionResult Create(Song songToCreate)
{
    try
    {
        db.Songs.Add(songToCreate);
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    catch (Exception ex)
    {
        SetGenreViewBag();
        return View();
    }
}