Search code examples
c#.netasp.net-mvcdropdownlistfor

DropDownListFor no ViewData item of type IEnumerable


Model:

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

    [Required(ErrorMessage = "Kategoria jest wymagana!")]
    public string Kategoria { get; set; }

    [Required(ErrorMessage = "Kod jest wymagany!")]
    public string Kod { get; set; }
}

Controller:

public ActionResult DodajPrzedmiot()
{
    if (StaticFunctions.IfLogged())
    {
        using (var db = new DatabaseContext())
        {
            var cats = from b in db.Categories
                       select new { b.Kategoria };

            var x = cats.ToList().Select(c => new SelectListItem
            {
                Text = c.Kategoria,
                Value = c.Kategoria
            }).ToList();

            //List<SelectListItem> catList = new List<SelectListItem>();
            //foreach (var t in cats)
            //{
            //    SelectListItem s = new SelectListItem();
            //    s.Text = t.ToString();
            //    s.Value = t.ToString();
            //    catList.Add(s);
            //}
            ViewBag.Kategoria = x;
        }
        return View();
    }
    else
    {
        return RedirectToAction("Logowanie", "User");
    }
}

View:

<div class="form-group">
        @Html.LabelFor(model => model.Kategoria, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.DropDownListFor(model => model.Kategoria, null)
        </div>
    </div>  

The problem is that this list shows values that I selected from database, when I add an item with selected e.g. "Biurowe" category it adds informations to database but in the same time it gives me 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 'Kategoria'.

What should I change here?


Solution

  • The second parameter in @Html.DropDownListFor(model => model.Kategoria, null) should be the list of items which would be ViewBag.Kategoria in your case. I would even suggest that you use a different name like ViewBag.KategoriaList. I've run into problems sometimes when using the same name for list in ViewBag as that of the property being bound to DropDownList.

    Try this code:

    public ActionResult DodajPrzedmiot()
        {
            if (StaticFunctions.IfLogged())
            {
                using (var db = new DatabaseContext())
                {
                    var cats = from b in db.Categories
                               select new { b.Kategoria };
    
                    var x = cats.ToList().Select(c => new SelectListItem
                    {
                        Text = c.Kategoria,
                        Value = c.Kategoria
                    }).ToList();
    
                    ViewBag.KategoriaList = x;
                }
                return View();
            }
            else
            {
                return RedirectToAction("Logowanie", "User");
            }
        }
    

    In the View:

    <div class="form-group">
            @Html.LabelFor(model => model.Kategoria, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model => model.Kategoria, ViewBag.KategoriaList as IEnumerable<SelectListItem>)
            </div>
        </div>  
    

    You have to also populate the ViewBag in POST action. This is what your POST action should be:

    [HttpPost]
        public ActionResult DodajPrzedmiot(Item itm)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    using (var db = new DatabaseContext())
                    {
                        // try putting this code in a separate function and use that function in both actions to populate the ViewBag.
                        var cats = from b in db.Categories
                                   select new { b.Kategoria };
    
                        var x = cats.ToList().Select(c => new SelectListItem
                        {
                            Text = c.Kategoria,
                            Value = c.Kategoria
                        }).ToList();
    
                        ViewBag.KategoriaList = x;
    
                        if (itm.Ilosc_zakupiona - itm.Ilosc_wypozyczona < 0) throw new ArgumentOutOfRangeException();
                        itm.Ilosc_magazynowa = itm.Ilosc_zakupiona - itm.Ilosc_wypozyczona;
                        db.Items.Add(itm);
                        db.SaveChanges();
                    }
                }
                catch (System.Data.Entity.Infrastructure.DbUpdateException)
                {
                    ViewBag.ErrorMessage = "Istnieje już przedmiot o takiej nazwie i/lub kodzie!";
                    return View();
                }
                catch (ArgumentOutOfRangeException)
                {
                    ViewBag.ErrorMessage = "Ilość zakupiona i/lub wypożyczona nie mogą być mniejsze od zera!";
                    return View();
                }
            }
            return View();
        }