ASP.NEТ MVC 5 checkbox/radio buttons binding in action - c#

I've searched google/SO for a lot of time now. And I didn't find a decent answer. My question is simple. How can I bind the radio selected button or the checked checkboxes to my action.
NO HTML HELPERS(I think that most people use the radio button and checkbox helpers cuz they don't know actually how they work, and use them by heart).
Simple example:
<input type="checkbox" id="foo" name="foo" value="1" checked>
<input type="checkbox" id="foo2" name="foo" value="2">
<input type="checkbox" id="foo3" name="foo" value="3">
<input type="radio" id="male" name="foo10" value="male">
<input type="radio" id="female" name="foo10" value="female">
I read many examples using an object with IsChecked property inside etc. I just want to use a view model like this in my action:
public class FooViewModel {
public int ChosenRadioButtonId {get;set;}
public List<int> ChosenCheckboxes {get; set;}
}
(PS: I don't know if I am mistaking but those helpers generate flaw html - duplicate ids, and everyone knows the basic HTML principles that one id can be used only ONCE)

the name of the checkboxes should exactly be the same as the name in ViewModel, so try to change the names to ChosenCheckboxes[] if you wanna bind them to a list.

Related

Grouping radio buttons without name attribute

I've got a form similar to the below, the name attributes have been set with MVC model binding in mind.
At the moment I'm only able to select one radio between the two forms. I want to select a radio button for each form, i.e. one radio button selected per form at any given time. I can't find a way to do this whilst keeping my name attribute naming convention.
Any ideas, thanks.
<div class="form-group-1">
<input type="radio" name="Students[0].Answer1" value=""><br>
<input type="radio" name="Students[0].Answer2" value=""><br>
</div>
<div class="form-group-2">
<input type="radio" name="Students[1].Answer1" value=""><br>
<input type="radio" name="Students[1].Answer2" value=""><br>
</div>

Check if checkbox is checked MVC controller

On my MVC View I have a few checkboxes:
<form method="POST" id="formRegistration" action="Registration/SubmitRegistration" >
//Other code...
<input name="test1" type="checkbox" />
<input name="test2" type="checkbox" />
</form>
On the controller I get- using a POST request- the data and I insert it to the DataBase:
public void AddRegistered(Registration r)
{
//Other code...
dParameters.Add("test1", r.test1.ToString());
dParameters.Add("test2", r.test2.ToString());
//Other code...
}
The problem is that I keep getting a false value even if the checkbox is checked.
Wham am I missing?
So the first thing you should do it take a look at the actual data being sent to the server with chrome debug tools or similar. What you might find is that your checkbox value will be set to on if checked, or it will be missing completely if un-checked.
One suggestion in the comments was #Html.CheckBoxFor, but this also suffers the fact that nothing will be sent if the checkbox is un-checked and in specific situations that can still become a problem.
You have two solutions - fix it on the client, or fix it on the server.
Fix it on the client:
To do this, you'll need to (with javascript) add a hidden field for every checkbox. Forgive me, I'm not by an editor to test it out but it might look something like this (from memory):
$('input[type="checkbox"]').each(function(el) {
var hidden = $('<input type="hidden" />');
hidden.name = el.name;
el.after(hidden);
el.on("change", function(el) {
hidden.value = el.checked ? "true" : "false";
});
});
Fix it on the server:
To do this, you'll need to create a custom PropertyBinder which recognizes on as a boolean true. This would be set on a property-attribute level. You could alternatively override the global ModelBinder to do this so you don't need to specifically annotate a property for this to work.
Personally, I prefer the "fix it on the client" method, because you will get either true or false posted back to the server every time which is what you'd expect and is the closest to the way that HtmlHelper does it.
You are missing the value attribute:
<input name="test1" type="checkbox" value="true" />
<input name="test2" type="checkbox" value="true" />
As simple as that.
If you don't want to use HtmlHelper class you can do like this
<form method="POST" id="formRegistration" action="Registration/SubmitRegistration" >
<input name="test1" type="checkbox" value="#Model.test1" />
<input name="test2" type="checkbox" value="#Model.test2" />
test1 and test2 should be in your model class.

Input data is not returning by passing through object

I am passing the input data from the .cshtml page to the action method.
Here is my .cshtml page:
#model passingdata
<form asp-controller="Home" method="post" asp-action="About" >
<button class="btn-danger" type="submit" value="Submit"></button>
<div class="form-group">
<label>
<input asp-for="date" placeholder="Date" class="col-md-8" />
</label>
<label>
Select from these Four Classes
<input type="radio" name="class" asp-for="classselect1" id="classselect1" value="classselect1" class="col-md-4" /> <p> #Model.classname1</p>
<input type="radio" name="class" asp-for="classselect2" id="classselect2" value="classselect2" class="col-md-4" /> <p> #Model.classname2</p>
<input type="radio" name="class" asp-for="classselect3" id="classselect3" value="classselect3" class="col-md-4" /> <p> #Model.classname3</p>
<input type="radio" name="class" asp-for="classselect4" id="classselect4" value="classselect4" class="col-md-4" /> <p> #Model.classname4</p>
</label>
</div>
</form>
And here is my controller code which is invoked when i Click on the button.
[HttpPost]
public IActionResult About(passingdata p)
{
ViewData["Message"] = "Your application description page.";
Teacher.classselect1 = p.classselect1;
Teacher.classselect2 = p.classselect2;
Teacher.classselect3 = p.classselect3;
Teacher.classselect4 = p.classselect4;
Teacher.date = p.date;
return View();
}
The input data like date and bool value from the radiobutton is not passing through the object of the class which contain these variables.
Please help me in this.
If i remember correctly, the Name attribute of each radiobutton is how .net MVC will map the values to your model.
In this case, all of your names are "class", which essentially means you have 1 form field named class with 4 options.
I would recommend using the html helper classes, because they will automatically create the proper html for you. The answer to this post should help: When using .net MVC RadioButtonFor(), how do you group so only one selection can be made?
If you dont want to use the helper just remember that when you submit a form, the data that is posted is based on the name of each form field. .Net does some magic in the background to serialize your Model for you, but essentially you are just submitting data in the format "?prop1=val1&prop2=val2".
Update
I figure maybe I should clarify a little better why what you are doing is not working how you expect.
When you post or put data via a form, it passes the input fields (text box, radio button, checkbox, etc...) as either querystring params or are part of the body. Radio buttons work a little differently than other input type. For a radio button, there are multiple input elements, but only one of them is valid. That is handled by using the name attribute. In your case, all of the names are "class", which means that the only thing being passed to the server is a single "?class={val}" (val is the value of which ever radio button is selected).
If your passingdata model had a property called "class", it would be populated. If your goal is to populated all 4 of the classselect properties with different values, you would need the name of each radio button to be different. But if there was only one radio button with each name, then each property could only have 1 value. You would need multiple RadioButtons with the same name to have multiple values (only one of which is selectable for each property).
Hopefully that clarifies what is wrong and gets you in the right direction.

how to post array of unknown depth/length to c#/mvc

My background is primarily PHP, so i'm used to being able to use deep arrays in forms very easily. What I need is the c#/MVC equivelant of the following:
<input type="text" name="data[0][index_name][0]">
<input type="text" name="data[0][index_name][1]">
<input type="text" name="data[1][index_name][0]">
<input type="text" name="data[1][index_name][1]">
<input type="text" name="data[2][index_name][0][something_else]">
<input type="text" name="data[2][index_name][0]">
<input type="text" name="data[2][index_name][1]">
These could then be accessed in this way in php...
$_POST['data'][0]['index_name'][0];
$_POST['data'][0]['index_name'][1];
$_POST['data'][1]['index_name'][0];
$_POST['data'][1]['index_name'][1];
$_POST['data'][2]['index_name'][0]['something_else'];
$_POST['data'][2]['index_name'][0];
$_POST['data'][2]['index_name'][1];
I've tried looking at/looping over the formColletion object i receive, but the keys are simply the name attribute string, such as "data[2][index_name][0][something_else]," and there is no depth to the data.
How do I parse this data and put in some usable data type? I do not know how deep the array will be as the form changes dynamically on the front end.
So you have some context, this will is being used to build a "table" of data that has a flexible number of rows and columns and each row can be treated as a standard row or grouping row (meaning it contains other rows), so the data can, in theory, get very deep.
On a side note, i've also thought about cleaning up the data on the client side, but it appears there's nothing standard out there that supports this. Jquery.serialize and JQuery.serializeArray() do the same thing as C#/MVC and simply index everything with the full name attribute without taking into account the array indexes.
Thanks for any help!
I'm not sure about the deep aspect but if you post items with the same name then MVC reconstructs this as an array.
<input type="hidden" name="MyArray" value="1"/>
<input type="hidden" name="MyArray" value="2"/>
<input type="hidden" name="MyArray" value="3"/>
<input type="hidden" name="MyArray" value="4"/>
And on your controller
[HttpPost]
public ActionResult MyActionMethod(string[] MyArray)
{
// Do stuff with MyArray
}
You can also access the Request.Form collection in the controller. The key is from the name part of the input on the HTML form.
You can access it like this:
Request.Form["data[2][index_name][0][something_else]"]
Or iterate over it like this:
[HttpPost]
public ActionResult MyActionMethod()
{
foreach(var key in Request.Form.Keys)
{
var item = Request.Form[key];
// Do stuff with each item
}
}
Model Binding turned out to be the correct solution. It support recursion out of the box. Here is a nice write-up:
http://msdn.microsoft.com/en-us/magazine/hh781022.aspx

Get ID of a radio button with Selenium CSS selector

I just wanted to know that how can I get the ID of
<input type="radio" class="class1" id="radio1" />
with the help of CSS selectors in Selenium.
This is a more difficult and intriguing question than you might suppose. It is important to be aware that values for the HTML class attribute are not unique. Thus, it is quite possible (and in fact probable) that your HTML page may have multiple elements with the class set to "class1". So selecting strictly on the class will only work if your radio button is the first element on your web page with that class value. Working only with your example, a safer locator expression would be
selenium.GetAttribute("css=input.class1[type='radio']#id");
This matches only class1 elements that are radio buttons. It is much more specific--it correctly avoids prior elements that happen to also have the class1 value for the class attribute. But it is still not satisfactory--again it will match the first such element. You can improve further if, for example, you have more than one group of radio buttons. Say you wanted the first radio button in the second group from this code fragment...
<div id='group1'>
<input type="radio" class="class1" id="radio1" />
...
</div>
<div id='group2'>
<input type="radio" class="class1" id="radio1" />
...
</div>
... you could use a locator like this:
selenium.GetAttribute("css=#group2 .class1[type='radio']#id");
(Note that the space after '#group2' is important!)
However, the above is mostly to explain the problem rather than to provide a good answer, because the fundamental problem remains.
Most likely your code is really something like this, with multiple radio buttons all having the same type and same class, distinguishable only by position:
<input type="radio" class="class1" id="radio1" />
<input type="radio" class="class1" id="radio2" />
<input type="radio" class="class1" id="radio3" />
The only way to target one of these other than the first is by explicit indexing, but that requires you know the index a priori, e.g.:
selenium.GetAttribute("css=#group2 [type='radio']:nth-child(2)#id");
(For more on constructing CSS recipes for Selenium see my article and wallchart XPath, CSS, DOM and Selenium: The Rosetta Stone on Simple-Talk.com.)
I will give you an example:
selenium.GetAttribute("css=.class1#id");
Here is the link for the documentation http://release.seleniumhq.org/selenium-remote-control/0.9.2/doc/dotnet/Selenium.DefaultSelenium.GetAttribute.html

Categories