How to handle checkboxes in ASP.NET MVC forms?

2019-01-01 06:14发布

Caution: This question is over nine years old!

Your best option is to search for newer questions, or to search the answers below looking for your specific version of MVC, as many answers here are obsolete now.

If you do find an answer that works for your version, please make sure the answer contains the version of MVC you are using.
(The original question starts below)


This seems a bit bizarre to me, but as far as I can tell, this is how you do it.

I have a collection of objects, and I want users to select one or more of them. This says to me "form with checkboxes." My objects don't have any concept of "selected" (they're rudimentary POCO's formed by deserializing a wcf call). So, I do the following:

public class SampleObject{
  public Guid Id {get;set;}
  public string Name {get;set;}
}

In the view:

<%
    using (Html.BeginForm())
    {
%>
  <%foreach (var o in ViewData.Model) {%>
    <%=Html.CheckBox(o.Id)%>&nbsp;<%= o.Name %>
  <%}%>
  <input type="submit" value="Submit" />
<%}%>

And, in the controller, this is the only way I can see to figure out what objects the user checked:

public ActionResult ThisLooksWeird(FormCollection result)
{
  var winnars = from x in result.AllKeys
          where result[x] != "false"
          select x;
  // yadda
}

Its freaky in the first place, and secondly, for those items the user checked, the FormCollection lists its value as "true false" rather than just true.

Obviously, I'm missing something. I think this is built with the idea in mind that the objects in the collection that are acted upon within the html form are updated using UpdateModel() or through a ModelBinder.

But my objects aren't set up for this; does that mean that this is the only way? Is there another way to do it?

22条回答
君临天下
2楼-- · 2019-01-01 06:40

When using the checkbox HtmlHelper, I much prefer to work with the posted checkbox form data as an array. I don't really know why, I know the other methods work, but I think I just prefer to treat comma separated strings as an array as much as possible.

So doing a 'checked' or true test would be:

//looking for [true],[false]
bool isChecked = form.GetValues(key).Contains("true"); 

Doing a false check would be:

//looking for [false],[false] or [false]
bool isNotChecked = !form.GetValues(key).Contains("true"); 

The main difference is to use GetValues as this returns as an array.

查看更多
荒废的爱情
3楼-- · 2019-01-01 06:41

I know that this question was written when MVC3 wasn't out, but for anyone who comes to this question and are using MVC3, you may want the "correct" way to do this.

While I think that doing the whole

Contains("true");

thing is great and clean, and works on all MVC versions, the problem is that it doesn't take culture into account (as if it really matters in the case of a bool).

The "correct" way to figure out the value of a bool, at least in MVC3, is to use the ValueProvider.

var value = (bool)ValueProvider.GetValue("key").ConvertTo(typeof(bool));

I do this in one of my client's sites when I edit permissions:

var allPermissionsBase = Request.Params.AllKeys.Where(x => x.Contains("permission_")).ToList();
var allPermissions = new List<KeyValuePair<int, bool>>();

foreach (var key in allPermissionsBase)
{
     // Try to parse the key as int
     int keyAsInt;
     int.TryParse(key.Replace("permission_", ""), out keyAsInt);

     // Try to get the value as bool
     var value = (bool)ValueProvider.GetValue(key).ConvertTo(typeof(bool));
}

Now, the beauty of this is you can use this with just about any simple type, and it will even be correct based on the Culture (think money, decimals, etc).

The ValueProvider is what is used when you form your Actions like this:

public ActionResult UpdatePermissions(bool permission_1, bool permission_2)

but when you are trying to dynamically build these lists and check the values, you will never know the Id at compile time, so you have to process them on the fly.

查看更多
梦寄多情
4楼-- · 2019-01-01 06:41

The easiest way to do is so...

You set the name and value.

<input type="checkbox" name="selectedProducts" value="@item.ProductId" />@item.Name

Then on submitting grab the values of checkboxes and save in an int array. then the appropriate LinQ Function. That's it..

[HttpPost]
        public ActionResult Checkbox(int[] selectedObjects)
        {
            var selected = from x in selectedObjects
                           from y in db
                           where y.ObjectId == x
                           select y;                   

            return View(selected);
        }
查看更多
宁负流年不负卿
5楼-- · 2019-01-01 06:41

Using @mmacaulay , I came up with this for bool:

// MVC Work around for checkboxes.
bool active = (Request.Form["active"] == "on");

If checked active = true

If unchecked active = false

查看更多
明月照影归
6楼-- · 2019-01-01 06:44

Just do this on $(document).ready :

$('input:hidden').each(function(el) {
    var that = $(this)[0];
    if(that.id.length < 1 ) {

        console.log(that.id);
        that.parentElement.removeChild(that);

    }
});
查看更多
素衣白纱
7楼-- · 2019-01-01 06:47

In case you're wondering WHY they put a hidden field in with the same name as the checkbox the reason is as follows :

Comment from the sourcecode MVCBetaSource\MVC\src\MvcFutures\Mvc\ButtonsAndLinkExtensions.cs

Render an additional <input type="hidden".../> for checkboxes. This addresses scenarios where unchecked checkboxes are not sent in the request. Sending a hidden input makes it possible to know that the checkbox was present on the page when the request was submitted.

I guess behind the scenes they need to know this for binding to parameters on the controller action methods. You could then have a tri-state boolean I suppose (bound to a nullable bool parameter). I've not tried it but I'm hoping thats what they did.

查看更多
登录 后发表回答