63

I have a form with a list of checkboxes. A user can select all values, no values, or any in between. Example:

screenshot of Goal

I would like to write the result to the database as a comma separated list. In the example above, "Apple, Banana". I'm a bit confused how to create the model for this and how to get the results from the View to the Controller into a comma separated list?

KyleMit
  • 30,350
  • 66
  • 462
  • 664
PixelPaul
  • 2,609
  • 4
  • 39
  • 70

3 Answers3

123

Here's an example of how to do that.

HomeModel.cs

public class HomeModel
{
    public IList<string> SelectedFruits { get; set; }
    public IList<SelectListItem> AvailableFruits { get; set; }

    public HomeModel()
    {
        SelectedFruits = new List<string>();
        AvailableFruits = new List<SelectListItem>();
    }
}

HomeController.cs

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new HomeModel
        {
            AvailableFruits = GetFruits()
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(HomeModel model)
    {
        if (ModelState.IsValid)
        {
            var fruits = string.Join(",", model.SelectedFruits);

            // Save data to database, and redirect to Success page.

            return RedirectToAction("Success");
        }
        model.AvailableFruits = GetFruits();
        return View(model);
    }

    public ActionResult Success()
    {
        return View();
    }

    private IList<SelectListItem> GetFruits()
    {
        return new List<SelectListItem>
        {
            new SelectListItem {Text = "Apple", Value = "Apple"},
            new SelectListItem {Text = "Pear", Value = "Pear"},
            new SelectListItem {Text = "Banana", Value = "Banana"},
            new SelectListItem {Text = "Orange", Value = "Orange"},
        };
    }
}

Index.cshtml

@model DemoMvc.Models.HomeModel
@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        @using (Html.BeginForm("Index", "Home"))
        {
            foreach (var item in Model.AvailableFruits)
            {
                <div class="checkbox">
                    <label>
                        <input type="checkbox"
                               name="SelectedFruits"
                               value="@item.Value"
                               @if(Model.SelectedFruits.Contains(item.Value))
                               {
                                   <text> checked </text> 
                               } 
                               /> @item.Text
                        </label>
                    </div>
            }
            <div class="form-group text-center">
                <input type="submit" class="btn btn-primary" value="Submit" />
            </div>
        }
    </div>
</body>
</html>

Which should result in the following within the Post Action:

Post Action

Shadesz
  • 33
  • 4
Win
  • 61,100
  • 13
  • 102
  • 181
  • 3
    Very nice answer, it's just missing the "selected/checked" handling – Guillaume Feb 20 '17 at 14:46
  • 3
    Also, whenever `ModelState.IsValid` is `false`, when re-hydrating the index view, the `SelectedFruits` / checkboxes won't restored. – KyleMit Mar 22 '17 at 20:56
  • 1
    I'm very late to the party here but isn't this kinda cheating? You're prepopulating the selected fruits before sending the user to the view. I've got to echo @Guillaume's comment here... You're missing the selection handling - which incidentally is where I'm tripping up. – Ortund Jan 17 '18 at 14:33
  • 3
    @Guillaume you can do the checked handling with this code `
    `
    – Pepe0217 Aug 02 '17 at 22:15
  • 1
    @Ortund me too, selected checkboxes are not mapped to the controller – Alexandre Ribeiro Nov 18 '18 at 09:48
  • 3
    @AlexandreRibeiro we can get those checked boxes using this `var selectedFruits = Request.Form.GetValues("SelectedFruits");` – Aishwarya Shiva Jun 06 '19 at 19:50
  • i get null model at post method. – Prince Jul 13 '20 at 01:12
4

You can also do Using jquery.No need to change any controller or action.It will simply add the selected checkboxes value in the database table's column as a coma separated.Just add the code in the View Page.

 <div class="editor-field">

        @Html.HiddenFor(model => model.hobbies, new { htmlAttributes = new { id = "hobbies" } })
        Hobbies :
        <input type="checkbox" id="r" onchange="getSelected()" value="Reading" />
        Reading
        <input id="w" type="checkbox" value="Writing" onchange="getSelected()" />
        Writing

        <script>
            function getSelected() {
                var sList = "";
                $('input[type=checkbox]').each(function () {
                    if (this.checked) {
                        sList += this.value + ",";

                    }
                });
                $("#hobbies").val(sList);
            }
        </script>
        @Html.ValidationMessageFor(model => model.hobbies)
    </div>
Rinku Choudhary
  • 1,529
  • 1
  • 13
  • 22
  • 1
    This works for me. Just there is an error - it should be: `@Html.HiddenFor(model => model.hobbies, new { id = "hobbies" } )` or I'd rather use `@Html.Hidden("hobbies", string.Join(",", Model.hobbies), new { id = "hobbies" })` initially because otherwise you get the value as `String[]` – nickornotto Mar 19 '19 at 16:30
0

So I hit my head against the wall on a rather foolish issue with this... Be sure that everything you work with is a Property instead of a Variable. For example...

Model.Variable.VariableList<string> may render when loading the page... However when you submit the page, you won't have your values return.

Model.Property.PropertyList<string> will work however.

To be a bit more clear...

public class MyListClass 
{
  public string MyListName { get; set; } = "My List Name";

//next line will show your items, but will not have changes to the items
//returned because it's not a property aka with getter and setter.
  public List<CheckBoxItem> Items = new List<CheckBoxItem>;
}

public class MyModel
{
//next line will show your items, but will not have changes to the items
//returned because it's not a property aka with getter and setter.
  public MyListClass MyList = new MyListClass();

}

Correct way would be...

public class MyListClass 
{
  public string MyListName { get; set; } = "My List Name";

  public List<CheckBoxItem> Items { get; set; } = new List<CheckBoxItem>;
}

public class MyModel
{
  public MyListClass MyList { get; set; } = new MyListClass();

}

I do realize here that my... intelligence is showing... but to those also banging your head on every example in the world not working, I hope this helps you.

Rob K.
  • 519
  • 6
  • 16