10

How do you associate a MultiSelectList with a list of checkboxes?

eg. I pass something like this to the model

  model.Groups = new MultiSelectList(k.Groups, "Id", "Name", selectedGroups)

How should I render it? This doesn't work

<% foreach (var item in Model.Groups.Items) { %>
  <input type="checkbox" name="groups" value="<%=item.Value%>" id="group<%=item.Value%>" checked="<%=item.Selected?"yes":"no"%>" />
  <label for="group<%=item.Value%>"><%=item.Text%></label>
<% } %>

Error CS1061: 'object' does not contain a definition for 'Value'...

Is there a HTML Helper method that I can use?

(Then, unless it is straightforward, how should I then get the selected values back on the Controller when the form is submitted?)

2
  • How do you need those Groups in the controller? Would it be enough if you just received Group IDs from the form? Commented Mar 4, 2010 at 6:24
  • I'll just need to know if the selections has changed (ie. Which ones are checked when the form is submitted). But more importantly how to render the checkboxes Commented Mar 4, 2010 at 6:30

2 Answers 2

18

I just tested to see how we can see if the selection was changed.

public class Group {
    public int ID { get; set; }
    public string Name { get; set; }
}

//And some data to play with
var allGroups = new List<Group>();
allGroups.Add(new Group { ID = 1, Name = "one" });
allGroups.Add(new Group { ID = 2, Name = "two" });
allGroups.Add(new Group { ID = 3, Name = "three" });

var selectedGroups = new List<Group>();
selectedGroups.Add(allGroups[0]);
selectedGroups.Add(allGroups[2]);

var m = new MultiSelectList(allGroups, "ID", "Name", 
    selectedGroups.Select(x => x.ID));

//passed that data to the view with ViewData
ViewData["list"] = m;

The checkbox elements :

<% foreach (var item in (MultiSelectList)ViewData["list"]) { %>
    <input type="checkbox" name="groups" value="<%=item.Value%>"
        id="group<%=item.Value%>"
        <%=item.Selected ? "checked=\"checked\"" : String.Empty%>/>
    <label for="group<%=item.Value%>"><%=item.Text%></label>
<% } %>   

Accepted an int array in the action :

[HttpPost]
public ActionResult SomeAction(int[] groups) {
    if (groups != null) {
        var postedSelection = allGroups.Where(x => groups.Contains(x.ID));
        if (!selectedGroups.SequenceEqual(postedSelection)) {
            //selection was changed
        }
        else {
            //selection is the same
        }
    }
    else {
        //no group ID was posted
    }
}

I hope that gives some idea.

Sign up to request clarification or add additional context in comments.

1 Comment

I see, so it should be foreach (var item in Model.Groups) instead of foreach (var item in Model.Groups.Items) Thank you cagdas!
2

I just wanted to share my implementation using the example from above. I'm populating properties that are organized into key / value pairs in my database. In my example I store each property as a key value pair in a Dictionary. Each item in the Dictionary will contain a string key such as "Color" and a MultiSelectList with values like DataValueField="1", DataTextField="Black" etc...

VewModel Code

public Dictionary<string, MultiSelectList> Properties { get; private set; }

    private void SetProperties()
    {
        this.Properties = new Dictionary<string, MultiSelectList>();

        foreach(InventoryItemProperty property in new InventoryItemPropertyRepository().FindAllInventoryItemProperties())
        {
            this.Properties.Add(property.Key.Name, new MultiSelectList(property.Values, "Id", "Value"));
        }
    }

View markup

<div id="editor-inventory-item-properties">
        <% foreach(string key in Model.Properties.Keys){ %>
            <div class="editor-label">
                <label for="<%= key.ToLower() %>"><%= key %></label><br />
                <% foreach(var item in Model.Properties[key]){ %>
                    <input type="checkbox" 
                        id="<%= key.ToLower() + "-" + item.Text.ToLower() %>" 
                        name="inventoryItemPropertyValues" 
                        value="<%= item.Value %>" 
                        <%= item.Selected ? "checked=\"checked\"" : string.Empty %> />
                    <label for="<%= key.ToLower() + "-" + item.Text.ToLower() %>">
                    <%= item.Text %></label><br />
                <% } %>
            </div>
        <% } %>
    </div>

Controller Action code

//
    // POST: /Admin/InventoryItems/Create

    [HttpPost]
    public ActionResult Create(InventoryItem inventoryItem, int[] inventoryItemPropertyValues)
    {
        try
        {
            inventoryItem.Created = DateTime.Now;
            inventoryItem.LastUpdated = inventoryItem.Created;
            this.inventoryItemRepository.Add(inventoryItem);
            this.inventoryItemRepository.Save();

            if(inventoryItemPropertyValues != null)
            {
                SaveInventoryItemPropertyValues(inventoryItem.Id, inventoryItemPropertyValues);
            }

            return RedirectToAction("Details", new { id = inventoryItem.Id });
        }
        catch
        {
            throw;
            //return View();
        }
    }
private void SaveInventoryItemPropertyValues(int inventoryItemId, int[] inventoryItemPropertyValues)
    {
        for(int i = 0; i < inventoryItemPropertyValues.Length; i++)
        {
            this.inventory_Item_ProperytValueRepository.Add(new Inventory_Item_PropertyValue() { InventoryItemId = inventoryItemId, InventoryItemPropertyValueId = inventoryItemPropertyValues[i] });
        }

        this.inventory_Item_ProperytValueRepository.Save();
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.