DropdownList Data Annotation does not fire when the Textboxes and other controls are firing - asp.net-mvc-3

I have a form that has several controls in it. I added data annotation to display an error message to the user when the required field are left empty. The TextBoxes and other controls display the message, which is an "*" before the label name, but the dropdownlist does not not. Once the user get rid of all the error messages and click on submit again, then, the message for the dropdown box is display. How do I force the dropdown box to display the message at the same time with the textbox?
Additional information:
Here is a sample of my data annotation:
[MetadataType(typeof(UserMetaData))]
public partial class UserMeta
{
}
public class UserMetaData
{
[Required(ErrorMessage = "*")]
public int GenderID { get; set; }
//The gender ID is displayed in a dropdown
list with "Select" as the default option. Then, it has all the other genders
showing in the dropdown once it is clicked on.
[Required(ErrorMessage = "*")]
public DateTime DataOfBirth{ get; set; }
}
In my view, I am using
#Html.ValidationMessageFor(model => model.DataOfBirth) //This is working fine.
#Html.ValidationMessageFor(model => model.GenderID)
//Here is the dropdown
#Html.DropDownList("GenderID", null, "Select", new { style = "width:200px;", onchange = "ValidateDropdown()" })
//This is the one that is not working as expected. I could get it to work using javascript, but I am trying not to it if I there is a way to get it to work properly using data annotation.
Thank in advance for your help.

I could not get it to work properly on the server side. As a result, I had to write a JQuery function that does the validation for the dropdown on the client side. Then, I do the post only if there is a selection on the dropdown.

Related

Asp.net MVC Html.TextboxFor title and validation message conflict

I have a Asp.net MVC application(using Razor View) in which i am using Html.Textboxfor for textbox. Below is the code :
#Html.TextBoxFor(m => m.Textbox1, Model.Attributes)
The attributes i am adding for these are
Model.Attributes = new Dictionary<string,object>);
Model.Attributes .Add("size", "3");
Model.Attributes .Add("min", 0);
Model.Attributes .Add("max", 100);
Model.Attributes .Add("title", "Value");
So when i click on submit i am validating the Textbox and it shows the default title as error message when data outside the specified range is entered. Any way to prevent this from happening and add a custom error message different from title?
im not sure what u try to do but i think u need just use data anotation
[StringLength(100, MinimumLength=1, ErrorMessage = "error message here")]
public string title { get; set; }

asp mvc 3 multiselect listbox. map each selected option to collection element

For example we have a view model with fields:
public List<string> SelectedTestItems { get; set; }
public List<SelectListItem> AllTestItems { get; set; }
and view with:
#Html.ListBoxFor(x=>x.SelectedTestItems, Model.AllTestItems)
And now when i open the view, select 3 items in listbox and submit the form(via jquery $.post and $.serialize ), for some reason in controller I get view model with one item in SelectedTestItems collection, and this item is comma separated values that i selected in listbox (SelectedTestItems[0] = "1,2,3")
is it possible to map listbox to something like this:
SelectedTestItems[0] = "1",
SelectedTestItems[1] = "2",
SelectedTestItems[2] = "3" ?
Thank You !
I had tested here and I received each value separated. Can you show all your code? Maybe we can see what is wrong.

MV3 Duplicate Query String Values for CheckBox (true,false for boolean)

I've created a fairly straight forward page with a check box:
#using (Html.BeginForm("MyController", "MyAction", FormMethod.Get))
{
#Html.CheckBoxFor(x => x.MyCheckBox)
<input type="submit" value="Go!" />
}
The URL is populated with the MyCheckBox value twice!? As such:
MyAction?MyCheckBox=true&MyCheckBox=false
It only duplicates the value if the check box is true. If set to false it will only appear once in the query string.
The code above is simplified as I have a couple of drop downs and a textbox on the form which work fine. I don't think there's anything unusual about the code which I've left out from this question.
Has anyone had a similar issue with query string parameters being duplicated?
This behaviour is by design of the checkbox control. The standard HTML checkbox control passes no value if it is not checked. This is unintuitive. Instead, the ASP.Net checkbox control has 2 elements, the standard control which is visible and also a hidden control with a value of 'False'.
Therefore, if the checkbox is not checked, there will be one value passed: False.
If it is checked, there will be two values, True and False. You therefore need to use the following code to check for validity in your code:
bool checkboxChecked = Request.QueryString["MyCheckBox"].Contains("True");
Accepted answer is correct however in my case in a recent development the MVC behaviour is misleading.
The MVC Html.CheckBox(...) and Html.CheckBoxFor(...) generate an extra input of 'type=hidden' with the same ID as the checkbox control, leading to the duplicate URL parameters. I got around this problem by simply including the mark up desired as follows:
#if(checkTrue){
<input type="checkbox" id="MyCheckBox" name="MyCheckbox" checked="checked">
}else{
<input type="checkbox" id="MyCheckBox" name="MyCheckbox">
}
Would be better wrapped upin a helper to use in place of the MVC code so the value check is encapsulated.
As part of my application, the controller maintains sets of query parameters using both form injection and link injection using helpers in order to preserve state (of paging/filtering controls for example) when clicked to navigate within the same controller scope. As a result of this feature, the check box element is always set back to false if the standard MVC helpers are used. It's a good thing I noticed and did not waste much time on this bug.
In my model, I had a collection of checkboxes like so:
public class PrerequisitesViewModel
{
public List<StudentPrerequisiteStatusViewModel> PrerequisiteStatuses { get; set; }
}
public class StudentPrerequisiteStatusViewModel
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
In order to get everything to bind correctly, I had to actually convert the values from the querystring and parse them manually with the following code:
// fix for how MVC binds checkboxes... it send "true,false" instead of just true, so we need to just get the true
for (int i = 0; i < model.PrerequisiteStatuses.Count(); i++)
{
model.PrerequisiteStatuses[i].IsSelected = bool.Parse((Request.QueryString[$"PrerequisiteStatuses[{i}].IsSelected"] ?? "false").Split(',')[0]);
}
Alas, it works, but I can't believe this is necessary in MVC! Hopefully, someone else knows of a better solution.
I solve this issue with use #Html.HiddenFor
<input id="checkboxId" type="checkbox" value="true" onchange="changeCheckboxValue()">
#Html.HiddenFor(m => m.MyCheckBox, new { #id = "hiddenId" } )
<script>
function changeCheckboxValue() {
document.getElementById("checkboxId").value = document.getElementById("hiddenId").checked;
}
</script>

mvc 3 view data validation

i'm trying to put DropDownList validation to work.
in model:
[Required(ErrorMessage = "this field is required")]
public int ObjectTypeID { get; set; }
in view:
<div class="editor-field">
#Html.DropDownList("ObjectTypeID", string.Empty)
#Html.ValidationMessageFor(model => model.ObjectTypeID)
</div>
if the user leaves the selection empty i expect client side validation to alarm. but this does not happen.
what can be done?
The behavior of system types is that they must have a value when initalized. An integer has a value of "0". Change your model to accept a nullable int:
public int? ObjectTypeID { get; set; }
Just wondering, but why not use DropDownListFor?
For client side validation to work I think you need to turn on ClientValidationEnabled & UnobtrusiveJavaScriptEnabled in the web.config for your project, I believe you also need to reference the jquery.validate.unobtrusive.min.js script on your page?
1) You are not loading your dropdownlist
2) Use DropDownListFor in order to match validation with ddl

Strongly Typed RadioButtonlist

I want to get some options (say payment method cash, credit card etc.) and bind these to radio buttons. I believe there is no RadioButtonList in MVC 3.
Also, once radios are bound I want to show the previously selected option to the user while editing the answer.
As always you start with a model:
public enum PaiementMethod
{
Cash,
CreditCard,
}
public class MyViewModel
{
public PaiementMethod PaiementMethod { get; set; }
}
then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel();
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
and finally a view:
#model MyViewModel
#using (Html.BeginForm())
{
<label for="paiement_cash">Cash</label>
#Html.RadioButtonFor(x => x.PaiementMethod, "Cash", new { id = "paiement_cash" })
<label for="paiement_cc">Credit card</label>
#Html.RadioButtonFor(x => x.PaiementMethod, "CreditCard", new { id = "paiement_cc" })
<input type="submit" value="OK" />
}
And if you want some more generic solution which encapsulates this in a helper you may find the following answer helpful.
This is how I like to bind RadioButtonLists. The view model has a collection of my strongly typed objects. For example, maybe PaymentOptions is a code table. Along with the collection is a SelectedPaymentOptionKey (or Selected*Id if you prefix your primary keys with Id). Initially this key will just be default 0, but on postback, it will hold the value of the selected item.
public class PaymentSelectionVM
{
public ICollection<PaymentOption> PaymentOptions { get; set; }
public int SelectedPaymentOptionKey { get; set; }
}
public ViewResult PaymentSelection()
{
var paymentOptions = db.PaymentOptions.ToList();
return View(
new PaymentSelectionVM {
PaymentOptions = paymentOptions,
//This is not required, but shows how to default the selected radiobutton
//Perhaps you have a relationship between a Customer and PaymentOption already,
//SelectedPaymentOptionKey = someCustomer.LastPaymentOptionUsed.PaymentOptionKey
// or maybe just grab the first one(note this would NullReferenceException on empty collection)
//SelectedPaymentOptionKey = paymentOptions.FirstOrDefault().PaymentOptionKey
});
}
Then in the View:
#foreach (var opt in Model.PaymentOptions)
{
#*Any other HTML here that you want for displaying labels or styling*#
#Html.RadioButtonFor(m => m.SelectedPaymentOptionKey, opt.PaymentOptionKey)
}
The m.SelectedPaymentOptionKey serves two purposes. First, it groups the Radio buttons together so that the selection is mutually exclusive(I would encourage you to use something like FireBug to inspect the generated html just for your own understanding. The wonderful thing about MVC is the generated HTML is fairly basic and standard so it shouldn't be hard for you to eventually be able to predict the behavior of your views. There is very little magic going on here.). Second, it will hold the value of the selected item on postback.
And finally in the post handler we have the SelectedPaymentOptionKey available:
[HttpPost]
public ActionResult PaymentSelection(PaymentSelectionVM vm)
{
currentOrder.PaymentOption = db.PaymentOptions.Find(vm.SelectedPaymentOptionKey);
....
}
The advantage of this over using SelectListItems is you have access to more of the object's properties in the case that you are displaying a grid/table and need to display many values of the object. I also like that there are no hard coded strings being passed in the Html helpers as some other approaches have.
The disadvantage is you get radio buttons which all have the same ID, which is not really a good practice. This is easily fixed by changing to this:
#Html.RadioButtonFor(m => m.SelectedPaymentOptionKey, opt.PaymentOptionKey, new { id = "PaymentOptions_" + opt.PaymentOptionKey})
Lastly, validation is a bit quirky with most all of the radio button techniques I've seen. If I really needed it, I would wire some jquery up to populate a hidden SelectedPaymentOptionsKey whenever the radio buttons are clicked, and place the [Required] or other validation on the hidden field.
Another workaround for the validation problem
ASP.NET MVC 3 unobtrusive validation and radio buttons
This looks promising but I haven't had a chance to test it:
http://memoriesdotnet.blogspot.com/2011/11/mvc-3-radiobuttonlist-including.html
You should bind your options to SelectList in ViewModel and set Selected attribute to true for previously selected option

Resources