MVC #Html.CheckboxFor submits true,false on form submission - asp.net-mvc

I am using MVC 5 with EF Code First and have a View model that contains a bool:
public bool MyCheckbox { get; set; }
I initialize this in my View's get:
model.MyCheckbox = true;
In the View:
#Html.CheckBoxFor(m => m.MyCheckbox)
Which get rendered as:
<input checked="checked" data-val="true" data-val-required="The field is required." id="MyCheckbox" name="MyCheckbox" type="checkbox" value="true" />
<input name="MyCheckbox" type="hidden" value="false" />
One of my Buttons on the View triggers an Ajax POST to the Controller where I want to look at the checkbox value:
bool bValue = Request["MyCheckbox"] == "true";
But the value of Request["MyCheckbox"] is "true,false" due to the extra hidden field with name="MyCheckbox".
How do I view the value of this checkbox in the controller with Request["..."] and make sense of it (either true or false)?
I also have another bool member in the View model and I use it in a hidden field intentionally. In the model:
bool MyHiddenBool { get; set; }
In the Controller Get:
model.MyHiddenBool = true;
In the View:
#Html.HiddenFor(x => x.MyHiddenBool)
In the Controller (via Ajax POST):
bool AnotherBool = Request["MyHiddenBool"] == "true";
But the value of Request["MyHiddenBool"] is either "True" or "False" instead of "true" and "false".
What gives with this inconsistency and how can I reliably see the values of these two methods of bools in my Views?

The problem is how you are consuming the form request variable.
In ASP.NET MVC there's probably never a good reason to use Request.Form or it's variants to consume your request data. You need to make a model or put in an argument for the action.
[HttpPost]
public ActionResult PostedForm(bool myHiddenBool)
{
//Frameworks model binder will extract the form field into your variable based on the name
}
The following copied from this answer.
This isn't a bug, and is in fact the same approach that both Ruby on
Rails and MonoRail use.
When you submit a form with a checkbox, the value is only posted if
the checkbox is checked. So, if you leave the checkbox unchecked then
nothing will be sent to the server when in many situations you would
want false to be sent instead. As the hidden input has the same name
as the checkbox, then if the checkbox is unchecked you'll still get a
'false' sent to the server.
When the checkbox is checked, the ModelBinder will automatically take
care of extracting the 'true' from the 'true,false'

Related

How to pass a hidden field value from one controller to another controller using Asp.net MVC Razor

I am trying to pass a hidden field value from a view in one controller to another controller. I tried the below code:
#using (Html.BeginForm("AddToCart","Cart"))
{
<input type="hidden" id="testName" value= #model[0].tblProd[0].ProductName />
}
and tried to retrieve that code in a controller called "Cart" as follows:
public ViewResult AddToCart(FormCollection collection1)
{
string prodName = Request["testName"];
return View();
}
But it's not work. Can someone assist me in solving this.
When a form is submitted, the values are sent to the server using the name property.
In your example the input only has an id.
Try:
<input type="hidden" id="testName" name="testName" value= #model[0].tblProd[0].ProductName />
Also, you can let default model binding take care of reading the POSTed values and setting properties for you so you don't have to do it manually with Request["testName"]:
public ViewResult AddToCart(FormCollection collection1, string testName)

Html.HiddenFor handles string and int differently

My model:
public class VerifyModel
{
public string PIN { get; set; }
public int Attempts { get; set; }
}
My view:
#Html.HiddenFor(m => m.PIN)
#Html.HiddenFor(m => m.Attempts)
On entry into the view, I inspect Model.PIN and Model.Attempts and they contain the correct values passed from the controller, where Attempts is non-zero. The Html rendered is however:
<input id="PIN" name="PIN" type="hidden" value="xxxx" />
<input data-val="true" value="0" data-val-number="The field Attempts must be a number." data-val-required="The Attempts field is required." id="Attempts" name="Attempts" type="hidden"/>
The value of Attempts is always 0! And I did not specify anywhere that the Attempts field is mandatory.
How do I solve the problem of int properties in the model?
If I've understood your question correctly, you're having problems with Attempts not incrementing after the form is posted back with an incorrect PIN. If that assumption is correct then you're experiencing this problem because of the way ModelState works.
The short answer to the problem is simply to call ModelState.Remove from your action:
[HttpPost]
public ActionResult YourAction(VerifyModel model)
{
ModelState.Remove("Attempts");
model.Attempts++;
return View(model);
}
If you'd like a full explanation of why this is the case, see ASP.NET MVC’s Html Helpers Render the Wrong Value!. Excerpt:
Why?
ASP.NET MVC assumes that if you’re rendering a View in response to an HTTP POST, and you’re using the Html Helpers, then you are most likely to be redisplaying a form that has failed validation. Therefore, the Html Helpers actually check in ModelState for the value to display in a field before they look in the Model. This enables them to redisplay erroneous data that was entered by the user, and a matching error message if needed.

HTML.CheckBox Behaviour

I am using a model where a check box is there . where i am posting the form i always get more than one boolean value, Code is as follow
//controller code
// GET: /Home/
// GET: /Home/Test
public ActionResult HomeTest()
{
HomeTest ht = new HomeTest();
return View(ht);
}
[AcceptVerbs(HttpVerbs.Post)]
[ValidateInput(false)]
public ActionResult HomeTest(FormCollection collection, HomeTest model)
{
string str = collection["test"].ToString();
return View(model);
}
//View Html
<%= Html.CheckBox("test") %>
I am getting following value in str while debugging "true,false". Am i do anything wrong?
This is how Html.CheckBox was designed!
It always renders
<input name="test" type="checkbox" value="true" />
followed by a
<input name="test" type="hidden" value="false" />.
When you submit the form with the checkbox checked, you'll get test=true,false and when the checkbox is unchecked, you get test=false.
This is how it supports binding to a boolean value, because the ,false part is ignored. However, if you're binding to something else (such as string), that's when you'll see the "true,false" value.
If you want different behavior, you'll have to roll-your-own Html.CheckBoxAlt method. Here's a similar question, along with some code, that I wrote a while back: Passing checkbox selection through to an action
MVC does things this way so it can tell the difference between "There is no checkbox called 'test'" and "The checkbox called 'test' is unchecked." Since HTML doesn't provide any built-in way to tell the difference, MVC makes it always send a "false" value, which will get overridden by a "true" value if you check the box.
The easiest solution is to make better use of MVC's approach. Rather than using the FormCollection, just use a parameter that the model binder can bind to:
public ActionResult HomeTest(bool test, HomeTest model)

in asp.net mvc default binding, what control on the view would map to a boolean as a parameter in the controller action

in asp.net mvc, it seems like checkboxes bind to array of strings (if they are checked). is there any view control that will bind to a boolean in my controller action
public ActionResult Go(bool isBold)
{
}
In your view you can use the Html.CheckBox helper:
<%= Html.CheckBox("isBold") %>
This will in fact render two HTML input fields:
<input type="checkbox" name="isBold" value="..." />
<input type="hidden" name="isBold" value="false" />
This is why it might appear that "bool" binds to arrays of booleans, which isn't exactly true.
The reason there are two inputs is that checkboxes that are unchecked post no value at all. That means ASP.NET MVC can't tell the difference between "this wasn't posted at all" as opposed to "this was posted but it was not checked."
By having two inputs ASP.NET MVC is guaranteed to always get at least one input. Then it just looks at the first. Here's what happens:
If the checkbox is checked, it sees "true,false" and picks the first value: true.
If the checkbox is unchecked it sees "false" and picks the first value: false.
You can still use other helpers with boolean input values, such as Html.TextBox or Html.DropDownList. The only thing that ASP.NET MVC cares about is that the first posted value with that name either says "true" or "false".

How can I get Html.CheckBox() as boolean during POST in custom IModelBinder?

I am using Html.CheckBox(). The resulting HTML is:
<input id="IsMultiGraph" name="IsMultiGraph" value="true" type="checkbox">
<input name="IsMultiGraph" value="false" type="hidden">
On the server I have an Action which is accepting the form post information and using a custom IModelBinder to bind the form results to one of my models. Here is a snippet of the code I am running in the IModelBinder:
bool isMultiGraph;
if (!bool.TryParse(bindingContext.HttpContext.Request["IsMultiGraph"], out isMultiGraph))
bindingContext.ModelState.AddModelError("IsMultiGraph", "Invalid boolean for \"IsMultiGraph\""); //this should not ever happen unless someone is programatically posting
result.IsMultiGraph = isMultiGraph;
The problem is that since Html.CheckBox() is rendering a checkbox as well as a hidden input field if I change the state of the textbox the postback value is doubled (ie. "true,false").
I understand why this is done and I'm looking for the best way to parse the current value of the CheckBox during a postback (checked = true, unchecked = false). Is there another helper method in MVC for this or should I just write my own?
One way is to use the GetValues method of the NameValueCollection class in order to get the first value of the array property like this:
bindingContext.HttpContext.Request.Form.GetValues("IsMultiGraph")[0]

Resources