Search code examples
c#asp.net-mvcdrop-down-menuviewbag

How to get a unique list of options from a model to populate a selectbox


I am trying to allow dynamic filtering of a view in MVC.

after a bit of faffing I tried this...which sort of worked

The select control extracts a unique set of values from the model to make the options

 foreach (var i in Model.Select(s => new{s.ListId, s.ListName}).Distinct())
            {
    <option value="@i.ListId">@i.ListName</option>

                }

This works fine until you have filtered. Once you have run the filter you have only the option that you already filtered (ie if you chose to filter on ListID1, the only select option is ListID1)

so...

in the controller, I have set up a list from the unfiltered model and shoved that in ViewBag

public async Task<IActionResult> Index(int? ListID)
    { var listoflists = (from l in _context.UgPoints
                          select new { l.ListId, l.ListName } ).Distinct();
        ViewBag.listoflists = listoflists;

then in the view I look at that

var lst = ViewBag.listoflists as IEnumerable<Draco2018MVC.Models.UgPoints>;

 {
            foreach (var l in lst)
            {
            <option value="@l.ListId">  @l.ListName</option>}
        }

but the lst variable is always null.

I am assuming that I have missed something fundamental, but I cannot see what.

Anybody able to suggest either

a better way to get a unique set of values to filter the rest of the page

or

what I am doing wrong with the viewbag

thanks


Solution

  • Your current controller code is generating a collection of annonymous items with ListId and ListName properties.

    Specifically this projection part of your line statement

    select new { l.ListId, l.ListName } 
    

    In your view, you are trying to cast it to a collection of your class, and it is failing, hence you get lst as null.

    You may create a list of SelectListItem object from your LINQ statement and set that to view bag.

    var listoflists = (from l in _context.UgPoints
                                     select new SelectListItem { 
                                                    Value= l.ListId.ToString(),
                                                    Text = l.ListName }
                      ).Distinct();
    ViewBag.listoflists = listoflists;
    

    Now in your view, you may even use the DropDownList helper method

    @Html.DropDownList("ListID",ViewBag.listoflists as IEnumerable<SelectListItem>)
    

    Keep in mind that, you are trying to call Distinct() method on a collection of UgPoints objects. When the type is a reference type, you probably want to override the Equals method of that to make it easier for the Distinct method code.

    Use of Distinct with list of custom objects

    Another option is get data from a source which does not have duplicate data. Perhaps a lookup table which has unique records. You probably need to make adjustments to your db design for that.