views:

1393

answers:

3

When I used the html Helper Checkbox, it produces 2 form elements. I understand why this is, and I have no problem with it except:

The un-checking of the checkbox does not seem to be in sync with the 'hidden' value.

What I mean is that when I have a bunch of checkboxes being generated in a loop:

<%=Html.CheckBox("model.MarketCategories[" & i & "].Value", category.Value)%>

and the user deselects and checkbox and the category.Value is FALSE, the code being generated is:

<input checked="checked" id="model_MarketCategories_0__Value" name="model.MarketCategories[0].Value" type="checkbox" value="true" />
<input name="model.MarketCategories[0].Value" type="hidden" value="false" />

This is wrong since the Value is False the checkbox should NOT be checked.

Any ideas why this is happening?

A: 

What's worse, is when it's submitted, it shows up as "true,false". Very frustrating.

When you check the box programmatically, it doesn't set the associated hidden field. You can easily work around this by writing the markup for the checkbox directly instead of using the MVC control.

I've had to do this myself just recently. It's a pet peeve of mine.

See this link for more information on this.

David Morton
A: 

This won't work for me because I am using Strongly Typed views/controllers.

I don't use:

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

I use:

public ActionResult ThisLooksWeird(MyCustomModelObject result)
{
  foreach (KeyValuePair<MarketCategory, Boolean> o in result.Categories) {
    If (o.Value == True) {
        // yadda
    }
  }
}

Now when I adapt my code to work as suggested in your posting, the Mapping between the two controls (checkbox/hidden) is still incorrect. It takes the value of the hidden component (which is always the value which was there when the page was loaded) instead of the checkbox which is what the value should be now.

BitFiddler
I have come to the conclusion that the checkbox helper is totally messed up when using strongly typed views/controllers. It's behavior is totally not what you would expect. It's state somehow is related to the last state it was in but I cannot decipher exactly what is going on. When all of my Dictionary members are "False" and therefore are passing "False" into the checkbox helper, sometimes the hidden value is false, sometimes it is true but always the checkbox seems to be checked... I am throughly confused.
BitFiddler
No matter what I do, the Checkbox html helper always generates a 'checked' checkbox (regardless of whether the value passed in to the function is true or false). How did this get passed testing?
BitFiddler
The weirdest thing is that when I use my 'clear all' and 'select all' controller actions, the checkboxes always come back selected. As soon as I start selecting/clearing them by hand, the checkbox seems to work properly. But the controller actions only set the values in the checkbox Dictionary to true/false. I don't see why this would make a difference?
BitFiddler
A: 

Okay, looks like David was right. It was my misunderstanding of exactly how the two fields work together that cause his solution not to work for me.

In case this helps anyone else here is my solution and how it works:

First I had to hand craft the two fields as David had described...

<input <%
         If category.Value = True Then
            %> checked <%
         End If
       %> class="filterCheckbox" id="model_MarketCategories_<%=i%>__Value" name="model.MarketCategories[<%=i %>].Value" type="checkbox" value="true" />
<input name="model.MarketCategories[<%=i%>].Value" type="hidden" value="False" />

Now a quick recap of why there are 2 fields:

// 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.

Now the reason both of the elements have the same name is this: If the browser will ignore all other input values with the same name once it has found one with a valid value. So if your browser always returns the value of the checkbox (regardless of whether it is checked or not) then the hidden element is ignored. If on the other hand your browser does not send the checkbox value if the checkbox is not checked, then the element immediately following the checkbox will set the value of the form property to false and return THAT.

My misunderstanding was that I thought the checkbox should always store the value of actual property, so something like:

<input <%
          If category.Value = True Then
             %> checked <%
          End If
       %> class="filterCheckbox" id="model_MarketCategories_<%=i%>__Value" name="model.MarketCategories[<%=i %>].Value" type="checkbox" value="<%=category.Value %>" />

This is what was causing issues... the checkbox 'value' should always be true. The hidden 'value' should always be false. And it is the state of the checkbox (checked or not) that will determine which gets returned to your controller.

Thanks David... sometimes the answer can be right in front of you but if your brain is not ready to receive, there's nothing a fellow programmer can do ;-)

BitFiddler