How to serialize the checkbox in a form into Json data - asp.net-mvc

We know that in MVC, a CheckBoxFor will generate a checkbox with a value="true" and a hidden with a value=false. Both input controls will share the same name.
It is very reasonable because the form will be able to POST a false value if the box is unchecked. And the model binder will ignore the hidden input when the checkbox return a true.
But now i have overridden the form submit event in order to send the form data into a WebAPI controller in JSON format.
When serializing the form data, there is no mechanism to parse the relationship between the checkbox and the hidden correctly. Therefore, when unchecked, it returns a false, which is okay. But when checked, it returns a {true, false} instead of true, because the serializeArray() function goes through every input and find two values goes to a same name.
The question is: What is the best way to correct it?

My solution to this problem was to write my own HtmlHelper method that renders a single <input type="checkbox" /> tag. Any other solution just seemed too hacky.
You can use dotPeek or .NET Reflector to look at how the Microsoft Team created the HtmlHelper.CheckboxFor method if you need any help accomplishing that task.
The 2 tag approach was taken to prevent MVC action parameters from throwing an exception when a "bool" parameter did not have a matching parameter sent to the controller (an unchecked checkbox doesn't send any value).

Related

Asp.Net MVC Model Binding with JQWidgets

When you want to create a DateTime picker control with JQWidgets, you must define a div element and then call a function like this using Javascript:
$("#MyDivElementId").jqxDateTimeInput().
The problem is: I'm not able to figure out how I can use Model Binding of Asp.Net MVC with this syntax. I mean, the Model Binding feature will try to match key-value pair received from input controls in the form element and obviously, div element are not input control.
I found somebody who already resolved this problem using hidden field set with values of matching div JQWidgets element before submitting form but I don't like this solution; it's not natural and I must write to much code for a thing that should be simpler in my view.
Does anybody have more elegant solution?
If you set the "name" attribute of the DIV tag, the value from the DateTimeInput's Input tag would be submitted.
First of all when you submit id is not submited and i just opened that plugin demo. when you add code $("#MyDivElementId").jqxDateTimeInput(). it will create textarea with name MyDivElementId and when you submit then you will have the same value on server side. Other issue can be with date format since they would be probably different on client side and server side.
try to add input parameter for controller "DateTime MyDivElementId" and check if its null or not.

About binding a checkbox to string property in MVC viewmodel

In my project I have a string field in the view model to display in a form and post back to the controller.
However for some reason, I'd like to display a checkbox, and retrieving string "True"/"False" from user input
I've searched through the internet and found this
How to render a model property of string type as checkbox in ASP.NET MVC
which leverage the editor template and achieve my need.
My question is that how do this be achieved, because in the editor template, I can only see it how to interpret the string to a checkbox, but it never explain or show how the checkbox value will be bind back to the string field with "True"/"False".
What should I do if I wanted "Yes"/"No" instead of "true"/"false", are there any converter that I need to make to parsing the checkbox to string?
Sorry for my bad English and lack of mvc knowledge, I just started MVC and web development for a few days.
UPDATE:
1. I am using ViewModel to bind with the forms, so I need something like Html.CheckBoxFor(x=>x.value)
while x.value is a string, obviously it is not possible with the default CheckboxFor
I think what you are asking is how to save the value back into your database, which is more of a back-end C# or VB question.
As you know, when you submit a form on an HTML page, if a checkbox is ticked, it's value will be passed in the POST parameters back to the server:
front-end HTML:
<input type="checkbox" name="theCheckBox" value="Yes" />
back-end C# in Page_Load() or similar
if(Request.Form["theCheckBox"] == "Yes") {
// save value "Yes" into database
}
just remember that if the checkbox is NOT TICKED, Request.Form["theCheckBox"] will be null

How to mimic MVC's checkbox -> bool model binding?

I've got an editor template which renders out a checkbox:
#Html.CheckBoxFor(model => model.Follow)
Which renders something like this:
<input checked="checked" data-val="true" data-val-required="The Follow field is required." id="Follow" name="Follow" type="checkbox" value="true" />
<input name="Follow" type="hidden" value="false" />
AFAIK the hidden field is something to do with catering when an unchecked box isn't sent to the server or something.
Anyway, if i take a look at the Request.Form["Follow"] when the checkbox is checked, i see a value of "true,false".
How do i coerce a bool from this value? Do i simply ignore the second field? (e.g the hidden field).
I'm doing this is a base controller (protected method, invoked from child controller), so i don't have a strongly-typed view model, only the raw Request object.
Can anyone help? Or alternatively, if someone could point me to where in the MVC source code this happens, i could take a look myself, but not sure where to start looking.
You are correct the hidden field is just so the form will be submitted to the server. Because if the form had just checkboxes that are not checked then nothing will be submitted and the server would not know to set them to false.
You only require 1 hidden field per form, you do not need one per checkbox. But if your making your own control it is hard to tell if a hidden textbox is already on the field or not. If you know you are always going to have a textbox or select list etc somewhere else on your forms you do not need a hidden textbox at all
You can rename your hidden textbox to anything name it "dummy" or something different to the checkbox name so Request.Form["Follow"]; will only return the value of the check box not need to split. You never need to check the value of the "hidden textbox".
On a side note you shouldn't be using Request.Form["Follow"] you Action method should have a parameter like this instead "bool? follow"
MVC helper renders checkbox input control with two input fields, the checkbox and the hidden, because the browser do not send a value for checkbox input field if the checkbox is not selected. If you do not use auto mapping, you need to parse the input value that you receve from your form.
Use this simple rule to detect the checkbox:
var rawFollow = Request.Form["Follow"];
if (rawFollow.Contains("true"))
{
// do something
}
As far as i know, the extra hidden field is because if the checkbox is NOT checked, that input will not be submitted with the form and therefore we need the hidden field with the value of false.
So the only solution is can think of is this:
var rawFollow = Request.Form["Follow"];
var rawFollows = rawFollow.Split(',');
if (rawFollows.Count() > 1)
{
rawFollow = rawFollows[0];
}
But this seems hacky (and what about the order of the elements on the page, what if for some reason the hidden field was FIRST, then it would always evaluate to false), which is why i'm wondering how the MVC source does this.

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]

How can I get CheckBox to maintain checked state across postback in ASP.NET MVC?

I have an ASP.NET MVC project with a form. In the Action method that handles the POST verb I have a custom IModelBinder implementation that is binding the form data to my model instance. If there are errors I am using bindingContext.ModelState.SetAttemptedValue() and bindingContext.ModelState.AddModelError() to persist the submitted value and error message to the ModelState.
This works great and I can see the expected behavior occurring on my input controls that are rendered with Html.TextBox() (which calls through to Html.InputHelper()). When I use Html.CheckBox() (which also calls through to Html.InputHelper()) the state of my CheckBox is NOT output to th <input /> tag.
It seems to me like the Html.InputHelper() method is not using the AttemptedValue from the ModelState for input fields of type CheckBox.
Here is the code from ASP.NET MVC Html.InputHelper() method.
Why is it that the CheckBox attemptedValue is not output to the input tag. Is there something I am missing here or do I need to manually handle this case by checking the ModelState and setting the tag attribute myself?
Update 11/09
Here is the call to HtmlHelpers that I am using to output the CheckBox:
<%= Html.CheckBox("IsDerived") %>
And here is the call that I am using to register the Attempted Value:
string isDerivedRequestValue = !string.IsNullOrEmpty(bindingContext.HttpContext.Request["IsDerived"]) ? bindingContext.HttpContext.Request.Form.GetValues("IsDerived") [0] : null;
bindingContext.ModelState.SetAttemptedValue("IsDerived", isDerivedRequestValue);
I'm not sure if this is the best way to solve the problem or not, but since the Html.InputHelper() method is not checking the AttemptedValue for CheckBox controls I added the following to my controller which embeds the proper value from the ModelState into ViewData and seems to do the trick quite well.
ViewData["IsDerived"] = ViewData.ModelState.ContainsKey("IsDerived")
? bool.Parse(ViewData.ModelState["IsDerived"].AttemptedValue)
: false;
Make sure you are not explicitly setting the isChecked parameter value when you call Html.CheckBox() as that will override any value stored in ViewData.

Resources