Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two-Way Data Binding using jQuery Driven "Chosen" Drop Down

Alright, I have a jQuery version of Chosen applied to a select displaying properly on my page and I've done so with the following code. First I have a BaseController that sets a ViewBag property listing all of the possible categories:

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    try
    {
        _connection.Open();
        this.ViewBag.AvailableCategories = new MultiSelectList(_connection.Query<Category>("select * from Category"), "CategoryID", "Name");
    }
    catch (Exception ex)
    {
        throw new HttpException(500, ex.Message);
    }
    finally
    {
        _connection.Close();
    }

    base.OnActionExecuted(filterContext);
}

Next, when navigating to /Event/View/1 I have the EventController setup (NOTE this controller bases the aforementioned controller) with the following View method.

public ActionResult View(int id)
{
    Event evt = null;

    try
    {
        evt = Event.Where(_connection, id);
        if (evt == null)
        {
            throw new HttpException(404, "Oops! The event you're looking for does not exist.");
        }
    }
    catch (Exception ex)
    {
        throw new HttpException(500, ex.Message);
    }

    return View(evt);
}

It sets the model, as you can see, to the following model.

public class Event
{
    public int EventID { get; set; }
    public int BusinessID { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public int NeighborhoodID { get; set; }

    public IEnumerable<int> CategoryIds
    {
        get
        {
            if (Categories == null) { return new List<int>(); }
            return Categories.Select(c => c.CategoryID).AsEnumerable();
        }
    }

    public List<EventCategory> Categories { get; set; }
    public List<EventHours> Hours { get; set; }

    public static Event Where(IDbConnection connection, int id)
    {
        Event result = null;

        try
        {
            connection.Open();

            var sql =
                @"  select * from Event where EventID = @EventID
                    select * from EventCategory where EventID = @EventID
                    select * from EventHours where EventID = @EventID";
            using (var multiResult = connection.QueryMultiple(sql, new { EventID = id }))
            {
                result = multiResult.Read<Event>().FirstOrDefault();
                if (result != null)
                {
                    result.Categories = multiResult.Read<EventCategory>().ToList();
                    result.Hours = multiResult.Read<EventHours>().ToList();
                }
            }
        }
        finally
        {
            connection.Close();
        }

        return result;
    }
}

Finally I have the following markup in the view.

@Html.DropDownListFor(m => m.CategoryIds,
    ViewBag.AvailableCategories as MultiSelectList,
    new { multiple = "multiple", @class = "chzn-container" })

Now, as I stated at first, it's displaying properly and listing all of the categories as expected. However, even though the CategoryIds property does list in fact two selected categories, it's not setting them (or showing them for that matter) as selected in the Chosen drop down on load.

I am forced to only further assume that if a user selected a value from the Chosen drop down that it would not bind properly on post either because it does not change the HTML when an item is selected.

So, my question is this, how do I properly two-way data bind to a Chosen drop down in MVC?

like image 738
Mike Perrenoud Avatar asked Oct 17 '12 03:10

Mike Perrenoud


Video Answer


1 Answers

ListBoxFor is the helper you should use for multiselect lists

replacing

@Html.DropDownListFor(m => m.CategoryIds,
    ViewBag.AvailableCategories as MultiSelectList,
    new { multiple = "multiple", @class = "chzn-container" })

with

@Html.ListBoxFor(m => m.CategoryIds,
    ViewBag.AvailableCategories as MultiSelectList,
    new { multiple = "multiple", @class = "chzn-container" })

should do the trick

like image 170
Lukas Winzenried Avatar answered Oct 25 '22 15:10

Lukas Winzenried