-2

I've been reading several articles about how to present choices to users. Some use ListBoxFor, some use CheckBoxFor, and then there is this thing called MultiSelectList.

What I am (was) confused about was that each example seemed to have done it a totally different way, and none of them actually used the built in "SelectListItem" class but instead always created their own.

So I originally was going to post a question asking for general clarification, but I thought it would just be representative of all the other various post and repetitive.

So let me re-phrase: How do you use a "List" or a "MultiSelectList" to present a user a list of choices, including the option for them to be displayed as a list of Check boxes?

In other words, if I have the following 2 items in my Model, how would I display each of them as a typical choice list box, or a typical Check List box?

public List<SelectListItem> Widgets1 { get; set; }
public MultiSelectList Widgets2 { get; set; }
da_jokker
  • 954
  • 2
  • 12
  • 16
  • You have not even asked a question! Neither this question or any of your answers will help anyone. –  Apr 21 '16 at 22:31
  • you are correct. I saw that Stack Overflow showed me an option for "answer your own question and share the knowledge" so I guess that is what this post is. – da_jokker Apr 21 '16 at 22:44
  • That would be fine if you were actually answering a question, but there is no question so your self answer(s) make no sense –  Apr 21 '16 at 22:47
  • So I'm a bit confused.. is this like jeopardy? Do I have to say "How do I display data in a Checklist?" and then turn around and say "Here is how.." :) – da_jokker Apr 22 '16 at 14:08
  • Your not understanding what SO is. Its goal is to build a repository of questions and answers. A question needs a clear statement of a problem, the code associated with it, and an explanation of what is not working. You have done none of that. If you want to write your own blog, go ahead, but do not use SO for it. –  Apr 23 '16 at 06:21
  • Gotcha. It just seems like SO comes up almost anytime I search for code help so I wanted to put what I found out all in 1 spot that covers the different scenarios, in hopes that it may save others some time. As I mentioned, the other alternatives was that I could have "answered" all the other posts.... I'll try to reword the original topic better.. – da_jokker Apr 26 '16 at 15:41
  • Why in the world would you use `SelectListItem` for a list of checkboxes (refer [this answer](http://stackoverflow.com/questions/29542107/pass-list-of-checkboxes-into-view-and-pull-out-ienumerable/29554416#29554416) for how it should be done. –  Apr 27 '16 at 00:02
  • And why in the world would you create a 2nd identical `IEnumerable` from the 1st one using `myModel.WidgetMultiSelectList = new MultiSelectList(myChoices, "Value", "Text", mySelections);` (its just pointless code!). And setting the last parameter (`mySelections`) of `MultiSelectList` is ignored when binding to a property so that is pointless as well. –  Apr 27 '16 at 00:02

2 Answers2

0

Warning... just wanted to point out that the "CheckBox" option basically hangs once you get too many choices. (e.g. changed my loop to 500) and it basically won't submit.

the problem is traced back to the validation of the CheckBoxFor line. This can be fixed by changing the one line to...

                        @Html.CheckBoxFor(cc => cc.WidgetsAsCheckList[myIndex].Selected, new { data_val = "false",  htmlAttributes = new { @class = "form-control" } })

If I do this, I can have 1,500 items in the check list and the submit occurs in under 3 seconds

da_jokker
  • 954
  • 2
  • 12
  • 16
-1

So let's start with the Model. It is really basic and you can see that I'm just creating 3 Lists that will store the same data.

The primary difference here is that all of the examples I read, people where creating their own Item classes, where I wanted to simply use the built in "SelectListItem" class

public class FooModel
{
  [Display(Name = "WidgetCheckList")]
  public List<SelectListItem> WidgetsAsCheckList { get; set; }

  [Display(Name = "WidgetListBox")]
  public List<SelectListItem> WidgetsAsListBox { get; set; }

  [Display(Name = "WidgetMultiSelectList")]
  public MultiSelectList WidgetMultiSelectList { get; set; }

  //We have to create a bucket that not only some how 
  //auto-magically knowns what has been pre-selected in the 
  //original list, but provides the view something to store
  //the new selections in when returning to the controller.
  //I have to admit, I have no idea how this knows what was
  //pre-selected, but being new at MVC, there are things I 
  //just have to leave it as a mystery becuase it just works.

  [HiddenInput(DisplayValue = false)]
  public List<string> userSelectionsAsListBox { get; set; }

  [HiddenInput(DisplayValue = false)]
  public List<string> userSelectionsAsMultiSelectList { get; set; }

  public FooModel()
  {
    this.WidgetsAsCheckList = new List<SelectListItem>();
    this.WidgetsAsListBox = new List<SelectListItem>();
    this.WidgetMultiSelectList = new MultiSelectList(new List<SelectListItem>());
  }
}   

For the Controller, because this was a learning test, I just made up the data. The key here is that I build a List of SelectListItems and then used that same list to populate all 3 demo fields of the Model to show 3 different ways to work with the same data.

// ------------------------------------------------------------------------
[HttpGet]       //Display the Edit view
public ActionResult Edit()
{
    FooModel myModel = new FooModel;

    //For testing, here I'm going to Inject some Choices
    //So first we build a list of them
    List<SelectListItem> myChoices = new List<SelectListItem>();
    for (Int32 myIndex = 1; myIndex < 15; myIndex++)
    {
        SelectListItem myChoice = new SelectListItem();
        myChoice.Value = myIndex.ToString();
        myChoice.Text = "Choice " + myIndex.ToString();
        if ((myIndex % 2) == 0)
        {
            myChoice.Selected = true;
        }
        else
        {
            myChoice.Selected = false;
        }
        myChoices.Add(myChoice);
    }

    String[] mySelections = myChoices.Where(x => x.Selected == true).ToArray().Select(x => x.Value).ToArray();

    //Now we use that same list to populate all 3 variations in our model
    myModel.WidgetsAsCheckList.AddRange(myChoices);
    myModel.WidgetsAsListBox.AddRange(myChoices);
    myModel.WidgetMultiSelectList = new MultiSelectList(myChoices, "Value", "Text", mySelections); 

    return View(myModel);
}

Now for the view, I display each list. The first of course is a check box and the second and third are list boxes but use different underlying objects...

@* This displays the "list" of SelectListItems as Checkboxes but we have to do alot more work *@
<div class="form-group">
    @Html.LabelFor(model => model.WidgetsAsCheckList, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        <div class="form-control" style="overflow-y: scroll; height: 25em; width:280px;">
            @for (var myIndex = 0; myIndex < Model.WidgetsAsCheckList.Count; myIndex++)
            {
                @Html.CheckBoxFor(cc => cc.WidgetsAsCheckList[myIndex].Selected, new { htmlAttributes = new { @class = "form-control" } })
                @Html.HiddenFor(cc => cc.WidgetsAsCheckList[myIndex].Value, new { htmlAttributes = new { @class = "form-control" } })
                @Html.DisplayFor(cc => cc.WidgetsAsCheckList[myIndex].Text, new { htmlAttributes = new { @class = "form-control" } })
                <br />
            }
        </div>
    </div>

</div>

 @* This displays the "list" of SelectListItems as list box that does all the work for us *@
<div class="form-group">
    @Html.LabelFor(model => model.WidgetsAsListBox, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">                
        @Html.ListBoxFor(model => model.userSelectionsAsListBox, Model.WidgetsAsListBox, new { @class = "form-control", size = 25 })
    </div>
</div>

@* This displays the "MultiSelectList" as list box that does all the work for us *@
<div class="form-group">
    @Html.LabelFor(model => model.WidgetMultiSelectList, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.ListBoxFor(model => model.userSelectionsAsMultiSelectList, Model.WidgetMultiSelectList, new { @class = "form-control", size = 25 })
    </div>
</div>

And finally, when the user makes their own selections (or takes the pre-selected ones) and hits submit, we can get the results in the the controller simply by...

// ---------------------------------------------------------------------
[HttpPost]       
[ValidateAntiForgeryToken]
public ActionResult Edit(FooModel myFooModel)
{

    List<string> SelectedItemsFromListBox = myFooModel.userSelectionsAsListBox;

    List<string> SelectedItemsFromMultiSelectList = myFooModel.userSelectionsAsMultiSelectList;

    List<string> SelectedItemsFromCheckList = myFooModel.WidgetsAsCheckList.Where(x => x.Selected == true).ToList().Select(x => x.Value).ToList();

}
da_jokker
  • 954
  • 2
  • 12
  • 16