Using Html.RadioButtonFor with a boolean isn't writing Checked="Checked" - asp.net-mvc-3

I am having an issue using the RadioButtonFor helper. When the value passed in is true, it isn't displaying a "check" in either radio button. When the value is false, it works just fine.
I copied this code from the project I am working on and created a sample application and I was able to replicate the issue. If I hard coded the value to true or false it seems to work, but when I use the "!string.IsNullOrEmpty(allgroups)" it doesn't.
From the View:
<div>
#Html.RadioButtonFor(m => m.AllGroups, true) All Groups
#Html.RadioButtonFor(m => m.AllGroups, false) Current Groups
</div>
From the ViewModel:
public bool AllGroups { get; set; }
From the Controller:
public ActionResult Index(string allgroups)
{
var model = new ProgramGroupIndexViewModel
{
AllGroups = !string.IsNullOrEmpty(allgroups)
};
return View(model);
}
From view source in IE:
<div>
<input id="AllGroups" name="AllGroups" type="radio" value="True" /> All Groups
<input id="AllGroups" name="AllGroups" type="radio" value="False" /> Current Groups
</div>
From view source when value of AllGroups is false (note it works):
<div>
<input id="AllGroups" name="AllGroups" type="radio" value="True" /> All Groups
<input checked="checked" id="AllGroups" name="AllGroups" type="radio" value="False" /> Current Groups
</div>

The model binding is getting confused because you named your action parameter the same as your model property. Change the name of your Index action parameter, and it should work.
public ActionResult Index(string showAllGroups)
{
var model = new ProgramGroup
{
AllGroups = !string.IsNullOrEmpty(showAllGroups);
};
return View(model);
}

if you are returning bool from model then there is no need to check uncheck explicitly mvc will do it itself just write
<div>
#Html.RadioButtonFor(m => m.AllGroups)
#Html.RadioButtonFor(m => m.AllGroups)
</div>
however if you want to do it explicitly then
you should use following syntax to check / uncheck
Html.RadioButtonFor(m => m.AllGroups, "DisplayText", new { #checked = "checked" })
In source code you can see that it is setting true / false for value not checked attribute
in your view you can write
#if(m.AllGroups)
{
Html.RadioButtonFor(m => m.AllGroups, "DisplayText", new { #checked = "checked" })
}
else
{
Html.RadioButtonFor(m => m.AllGroups, "DisplayText" })
}

Related

mvc3 checkbox value after submit

I have a form with 2 fields a dropdownlist and a checkbox. I have everything working correctly but i can not for some reason obtain the value of a checkbox if it is checked this is my code..
[HttpPost]
public ActionResult view(string pick)
{
switch (pick)
{
case "Deny":
// capture checkbox value here
break;
case "Accept":
// capture checkbox value here
break;
}
return View();
}
This is my view
#using (Html.BeginForm("view", "grouprequest", FormMethod.Post, new {}))
{
#Html.DropDownList("pick", new SelectList(new List<Object>{
new{ Text ="Accept", Value= "Accept"},new{ Text ="Deny", Value= "Deny"}}, "Value", "Text"), new {})
<input type="submit" name="work" id="work" value="Update" style="font-size:16px" />
foreach (var item in Model)
{
<input type="checkbox" id="#item.grouprequestID" name="#item.grouprequestID" value="#item.grouprequestID" />
}
}
Basically the dropdownlist has 2 options which are Accept and Deny I can capture which one the user chooses via the SWITCH-case in the controller now how can I capture the value of the checkboxes? If you notice the Checkboxes have a variable to them named #groupRequestID so every checkbox has a different unique value like 1,2,3 etc.. any help would be greatly appreciated !!
The Model
public class grouprequest
{
[Key]
public int grouprequestID { get; set; }
public int? profileID { get; set; }
public int? registrationID { get; set; }
public DateTime expires { get; set; }
public int? Grouplink { get; set; }
}
Check boxes when posted to the server act a little strange.
If a box is checked the browser will send name=value as in
<input type="checkbox" name="name" value="value" />
But if the checkbox is not checked the server doesn't send anything.
<input type="checkbox" name="Check1" id="Checks1" value="Hello" checked="checked"/>
<input type="checkbox" name="Check1" id="Checks1" value="Hello1" />
<input type="checkbox" name="Check1" id="Checks1" value="Hello2" />
Will result in Check1 = Hello
What this means is if all your check boxes are related, naming them the same will populate the same attribute of your ActionMethod. If that attribute is an enumeration it will contain only the ones that are checked.
If you have this in your view:
<input type="checkbox" name="MyValues" value="1" checked="checked"/>
<input type="checkbox" name="MyValues" value="2" />
<input type="checkbox" name="MyValues" value="3" />
and this as your controller action method:
public ActionMethod MyAction(IEumerable<int> myValues)
The myValues variable will look like this:
myValues[0] == 1
You should also note that if you are using the Html helper extension:
#Html.CheckBoxFor(m => m.MyValue)
Where MyValue is a bool the extension will create a checkbox input tag and also a hidden input tag with the same name, meaning a value will always be passed into the controller method.
Hope this helps.

Approve and Reject in ASP.NET MVC3

I know this question is not that hard but I'm new to asp.net mvc3 and I don't have an idea how to do this. I created a simple CRUD function in my controller. Now in my edit I changed the textbox to a two radio button Approve and Reject. Now my question is how could I let my edit get the value of the radio button that I choose? Here are the value of my radio buttons in my View>Edit
My VIEW>EDIT
<div class="editor-label">
#Html.LabelFor(model => model.Status)
</div>
<div class="editor-field">
<input type="radio" name="action" value="Approve" />Approve
<input type="radio" name="action" value="Reject"/>Reject
</div>
Here is the Edit in my Controller I don't know what to modify here.. :(
public ActionResult Edit(int id)
{
Leave leave = db.Leaves.Single(l => l.leave_id == id);
return View(leave);
}
[HttpPost]
public ActionResult Edit(Leave leave)
{
if (ModelState.IsValid)
{
db.Leaves.Attach(leave);
db.ObjectStateManager.ChangeObjectState(leave, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(leave);
}
Here is the model of my leave
Try to use Html.RadioButtonFor() helper:
#Html.RadioButtonFor(model => model.Status, "Approve") Approve
#Html.RadioButtonFor(model => model.Status, "Reject") Reject
instead of
<input type="radio" name="action" value="Approve" />Approve
<input type="radio" name="action" value="Reject"/>Reject
It depends from the type of your Status.
If it's bool than DevDave's example should work fine.
If it's string - than my first example should be ok.
But if it's int with values 0 for Reject and 1 for Approve - you should use something like this:
#Html.RadioButtonFor(model => model.Status, "1") Approve
#Html.RadioButtonFor(model => model.Status, "0") Reject
Assuming you use a bool value for Status:
<label for="approve">
#Html.RadioButtonFor(x => x.Status, "True", new { id = "approve" })
Approve
</label>
<label for="reject">
#Html.RadioButtonFor(x => x.Status, "False", new { id = "reject" })
Reject
</label>
Edit: It is bad practice to expose your db object, you should use a view model that has the relevant properties from your db object and then you can map between the two when saving/loading.
I.e. return LeavesViewModel to view, but convert your LeavesViewModel into db oject on save.
In the example provided, this should directly map to the Leave object that is passed into your Post method, assuming it is a bool value. Debug and you should see the value come back true or false depending on the option you choose.
It may also work if Status is an Enum with more than two (i.e. bool) options but I have not tried that before.
So in your edit view, wrap your radio buttons and other parts of the form in:
#using (Html.BeginForm("Edit", "ControllerName")) {
..your stuff
<input type="submit" value="Save" />
}

Checking a radio button

I want to check a radio button based on the culture which is set in the "culture" variable in the #helper method. During debugging, I know the the variable is set; it's just not checking the English or Spanish radio button.
Could someone tell me how I can do this based on the below code or if there is an easier way for the code, that would be fine too. I'm using MVC 3 Razor.
#helper selected(string c, string culture)
{
if (c == culture)
{
#:checked="checked"
}
}
<script type="text/javascript">
$(function () {
$("input[type='radio']").click(function () {
$(this).parents("form").submit();
});
// highlight selected language
$("input[type='radio']:checked").next().css("font-weight", "bold");
});
</script>
#using (Ajax.BeginForm("SetCulture", "Home", new AjaxOptions { UpdateTargetId = "setCulture" }))
{
<fieldset id="setCulture">
<legend>#Resources.SelectCulture</legend>
<input name="culture" id="en-us" value="en-us" type="radio" #selected("en-us", culture) />
<label for="en-us">
English</label>
<br />
<input name="culture" id="es-es" value="es-es" type="radio" #selected("es-es", culture) />
<label for="es-es">
EspaƱol</label>
<br />
</fieldset>
}
If your culture variable equaled either "en-us" or "es-es" what you have already should work. I don't think it equals what you think it does. You could try
<input name="culture" id="testing" value="testing" type="radio" #selected("testing","testing") />
to test what you have.
That said I'd recommend using the RadioButtonFor method with a strongly typed view
public class YourViewModel
{
public string Culture { get; set; }
// Other properties
}
#model YourViewModel
#*Rest of view*#
#Html.RadioButtonFor(m => m.Culture, "en-us")
#Html.RadioButtonFor(m => m.Culture, "es-us")

ASP.NET MVC 3 Model has no information on postback

I have a view with a couple of partial views that I bind to my model. For some reason, when I post, the model is empty, and I am not sure why.
Below is my ViewModel.
public class IndexViewModel
{
public bool AdvancedSearchOption { get; set; }
public bool ForceAdvanced { get; set; }
public bool ForceSimple { get; set; }
public string SimpleSearchCriteria { get; set; }
public string CustomerNumberCriteria { get; set; }
public string AccountNumberCriteria { get; set; }
public string NameCriteria { get; set; }
public string PhoneNumberCriteria { get; set; }
}
Here is my controller. I am filling in all the values of the viewmodel because I wanted to see if the values got to the partial views. They do get there, so it is just on the post that I am having issues.
public class HomeController : Controller
{
private ISecurityRepository SecurityRep;
public HomeController(ISecurityRepository repo)
{
SecurityRep = repo;
}
public ActionResult Index()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = false;
temp.ForceSimple = false;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria = "Acct";
temp.CustomerNumberCriteria = "Cust";
temp.NameCriteria = "Name";
temp.PhoneNumberCriteria = "Phone";
return View(temp);
}
public ActionResult SimpleSearch()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = false;
temp.ForceSimple = true;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria = "Acct";
temp.CustomerNumberCriteria = "Cust";
temp.NameCriteria = "Name";
temp.PhoneNumberCriteria = "Phone";
return View("Index",temp);
}
public ActionResult AdvancedSearch()
{
IndexViewModel temp = new IndexViewModel();
temp.AdvancedSearchOption = SecurityRep.DefaultToAdvancedSearch(User.Identity.Name);
temp.ForceAdvanced = true;
temp.ForceSimple = false;
temp.SimpleSearchCriteria = "Testing";
temp.AccountNumberCriteria= "Acct";
temp.CustomerNumberCriteria= "Cust";
temp.NameCriteria= "Name";
temp.PhoneNumberCriteria = "Phone";
return View("Index", temp);
}
[HttpPost]
public ActionResult Index(IndexViewModel vm, FormCollection formCollection)
{
return View();
}
}
Here is my view
#model TRIOSoftware.Magnum.Models.IndexViewModel
#{
ViewBag.Title = "Search";
}
#if ((#Model.AdvancedSearchOption && #Model.ForceSimple != true) || #Model.ForceAdvanced == true)
{
#Html.Partial("AdvancedSearch")
}
else
{
#Html.Partial("SimpleSearch")
}
Here is my SimpleSearch partial view. I think if I can get this one working, the other will follow the same path. I do the post in the partial and I use jQuery to do it. I am not sure if either of these things could cause me issues or not. I only have all the hidden items in there because I didn't know if not having them was causing my issues.
#model TRIOSoftware.Magnum.Models.IndexViewModel
<script type="text/javascript">
$(document).ready(function () {
$("#DefaultDiv").find("#DefaultAdvanced").click(function () {
$.post("DefaultSimple");
});
$("#SearchSection").find("#SearchButton").click(function () {
$.post("");
});
});
</script>
#using (Html.BeginForm("Index","Home"))
{
#Html.HiddenFor(m => m.ForceAdvanced)
#Html.HiddenFor(m => m.AdvancedSearchOption)
#Html.HiddenFor(m => m.ForceSimple)
#Html.HiddenFor(m => m.AccountNumberCriteria)
#Html.HiddenFor(m => m.CustomerNumberCriteria)
#Html.HiddenFor(m => m.NameCriteria)
#Html.HiddenFor(m => m.PhoneNumberCriteria)
<div id="DefaultDiv" style="float:right">
<a id="DefaultAdvanced" href="#" class="ButtonClass">Default Simple Search</a>
</div>
<div style="clear:both; margin: auto; width: 800px">
<img src="../../Content/images/TRIO_transparent_image.gif"; alt="TRIO Software"; style="margin-left:150px; clear:left"/>
<div style="clear:left; float: left" class="SearchText">
#Html.Label("What's your inquiry?:")
#Html.EditorFor(m => m.SimpleSearchCriteria, new { style = "width: 400px" })
</div>
<div id="SearchSection" style="float: left" class="SearchText">
<img src="../../Content/images/Search.gif"; alt="Search"; style="float:left" />
</div>
<p style="clear:left;margin-left:400px">
#Html.ActionLink("Advanced Search", "AdvancedSearch", null, new { style = "clear:left" })
</p>
</div>
}
Here is the HTML code when viewing the simple search partial view:
<div id="main">
<script type="text/javascript">
$(document).ready(function () {
$("#DefaultDiv").find("#DefaultAdvanced").click(function () {
$.post("DefaultSimple");
});
$("#SearchSection").find("#SearchButton").click(function () {
$.post("");
});
});
</script>
<form method="post" action="/">
<input type="hidden" value="False" name="ForceAdvanced" id="ForceAdvanced" data-val-required="The ForceAdvanced field is required." data-val="true">
<input type="hidden" value="False" name="AdvancedSearchOption" id="AdvancedSearchOption" data-val-required="The AdvancedSearchOption field is required." data-val="true">
<input type="hidden" value="False" name="ForceSimple" id="ForceSimple" data-val-required="The ForceSimple field is required." data-val="true">
<input type="hidden" value="Acct" name="AccountNumberCriteria" id="AccountNumberCriteria">
<input type="hidden" value="Cust" name="CustomerNumberCriteria" id="CustomerNumberCriteria">
<input type="hidden" value="Name" name="NameCriteria" id="NameCriteria">
<input type="hidden" value="Phone" name="PhoneNumberCriteria" id="PhoneNumberCriteria">
<div style="float:right" id="DefaultDiv">
<a class="ButtonClass ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="#" id="DefaultAdvanced" role="button"><span class="ui-button-text">Default Simple Search</span></a>
</div>
<div style="clear:both; margin: auto; width: 800px">
<img style="margin-left:150px; clear:left" alt="TRIO Software" ;="" src="../../Content/images/TRIO_transparent_image.gif">
<div class="SearchText" style="clear:left; float: left">
<label for="What_s_your_inquiry_:">What's your inquiry?:</label>
<input type="text" value="Testing" name="SimpleSearchCriteria" id="SimpleSearchCriteria" class="text-box single-line">
</div>
<div class="SearchText" style="float: left" id="SearchSection">
<a class="ButtonClass ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" id="SearchButton" ;="" href="#" role="button"><span class="ui-button-text"><img style="float:left" alt="Search" ;="" src="../../Content/images/Search.gif"></span></a>
</div>
<p style="clear:left;margin-left:400px">
<a style="clear:left" href="/Home/AdvancedSearch">Advanced Search</a>
</p>
</div>
</form>
</div>
How do I fix this problem?
Although you're selecting a partial to render, you're not passing it the model. There's an overloaded version of Html.Partial that takes a second argument that allows you to pass a model to it:
#Html.Partial("ViewName", Model);
So in your case, you'd use this:
#if ((Model.AdvancedSearchOption && Model.ForceSimple != true) || Model.ForceAdvanced == true)
{
#Html.Partial("AdvancedSearch", Model)
}
else
{
#Html.Partial("SimpleSearch", Model)
}
Also notice how I've removed the #s you were prefixing Model with. To better understand why, please see Introduction to ASP.NET Web Programming Using the Razor Syntax and a small reference for this same topic written by Phil Haack here.
I think #john-h hit the nail on the head with his answer. However, you might want to reduce the complexity you've created for yourself.
1) Since both ForceSimple and ForceAdvanced are Boolean, it would be assumed that when ForceAdvanced is true, then it's not "Simple", right? I'm not sure what other logic you have here.
2) Rather than creating two views and "posting" back to get the correct one, why not just use a parameter to set the search type? Or evaluate the security to set which one the user can execute. Here's an example:
Controller Actions:
//id is the search type: true is Advanced
public ActionResult Search(bool id) {
IndexViewModel viewModel = new IndexViewModel {
/* Do whatever logic here */
ForceAdvanced = (id) ? false : true,
AdvancedSearchOption = id
};
return View("search", viewModel);
}
[HttpPost]
public ActionResult Search(IndexViewModel model) {
//model.SimpleSearchCriteria = "Testing";
//model.PhoneNumberCriteria = "Phone";
return View("search", model);
}
Search View:
#using (#Html.BeginForm(new { id = #Model.AdvancedSearchOption })) {
<div style="clear:left; float: left" class="SearchText">
#Html.Label("What's your inquiry?:")
#if (Model.AdvancedSearchOption) {
<div>
#* if you really want, load your partial views here *#
<span>#Html.LabelFor(m => m.NameCriteria)</span>
#Html.EditorFor(m => m.NameCriteria, new { style = "width: 400px" })
<span>#Html.LabelFor(m => m.PhoneNumberCriteria)</span>
#Html.EditorFor(m => m.PhoneNumberCriteria, new { style = "width: 400px" })
</div>
}
else {
#* if you really want, load your partial views here *#
#Html.EditorFor(m => m.SimpleSearchCriteria, new { style = "width: 400px" })
}
</div>
<div>
<input type="submit" value="Search" />
</div>
#Html.HiddenFor(m => m.ForceAdvanced)
#Html.HiddenFor(m => m.AdvancedSearchOption)
#Html.HiddenFor(m => m.ForceSimple)
#Html.HiddenFor(m => m.AccountNumberCriteria)
#Html.HiddenFor(m => m.CustomerNumberCriteria)
#Html.HiddenFor(m => m.NameCriteria)
#Html.HiddenFor(m => m.PhoneNumberCriteria)
}
I had tried explicitly sending in the model to the partials with no luck. I believe that the partial views get the parent model by default if nothing is specified, so all I needed to do was to specify the model type in my partials, and I got the information.
I finally figured it out with a lot of trial and error. My issue was being caused by me trying to use jQuery to do a post. There must be some other things you need to do to update your model doing it this way. Once I changed it out and put an input control on the form for the post, I got all my data back from the parent and partial view in the controller.

Bind Checkboxes to int array/enumerable in MVC

#Html.CheckBox("orderNumbers", new { value = 1 })
#Html.CheckBox("orderNumbers", new { value = 2 })
#Html.CheckBox("orderNumbers", new { value = 3 })
#Html.CheckBox("orderNumbers", new { value = 4 })
#Html.CheckBox("orderNumbers", new { value = 5 })
[HttpPost]
public ActionResult MarkAsCompleted(IEnumerable<int> orderNumbers) { }
[HttpPost]
public ActionResult MarkAsCompleted(IEnumerable<string> orderNumbers) { }
If I use the first signature in my action method, I get an empty IEnumerable.
If I use the second signature I do receive the values but I also receive a false value for the unselected values (because of MVCs pattern of shadowing all checkboxes with a hidden field).
e.g. I will receive something like orderNumbers = { "1", "2", "false", "4", "false" }
Why can't I just get the list of numbers?
You can get all the checked values by the following way.
Controller code :
public ActionResult Index()
{
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(string[] orderNumbers)
{
return View();
}
View Code :
#using (Html.BeginForm())
{
<input name="orderNumbers" type="checkbox" value="1" />
<input name="orderNumbers" type="checkbox" value="2" />
<input name="orderNumbers" type="checkbox" value="3" />
<input name="orderNumbers" type="checkbox" value="4" />
<input name="orderNumbers" type="checkbox" value="5" />
<input type="submit" name="temp" value="hi" />
}
Please keep one thing in my mind that, you need to give same name to all checkboxes. In array you will get values for all checked checkboxes.
Because thats how the provided CheckBoxFor helper is working.
You have to generate the html for the checkboxes yourself. Then the hidden inputs are not generated and you will get only the selected integer values.
In addition to alok_dida's great answer. Since all the values are integers, you can have your controller code take an array of integers and avoid doing the conversion yourself.
This works in MVC4+:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(int[] orderNumbers)
{
return View();
}

Resources