mvc enum radio button required field - asp.net-mvc

I am displaying radio buttons using enum class.
public enum RegisteredBy
{
[Display(Name = "Customer", Order = 0)]
H,
[Display(Name = "Dealer/Contractor", Order = 1)]
S,
}
When i am rendering this on my view and on submit I am not selected any radio button. Even though it is taking "H" as default value. So that it is not showing any validation message.
#using ConsumerProductRegistration.Models;
#using ProductRegistration.Models.Enums;
#model ProductRegistration.Models.Registration
#Html.RadioButtonFor(m => m.RegisteredBy, RegisteredBy.H, new { id = "RegisteredByCustomer" })
#Html.Label("Customer")<br />
#Html.RadioButtonFor(m => m.RegisteredBy, RegisteredBy.S, new { id = "RegisteredByDealer" })
#Html.Label("Dealer/Contractor")
#Html.ValidationMessageFor(m => m.RegisteredBy)
In Model:
public class Registration
{
[Required(ErrorMessage = "Select at least one option")]
[Display(Name = "Registered by*")]
public RegisteredBy RegisteredBy { get; set; }
}
In view:
public ActionResult CustomerInfo(Registration registration)
{
return View(registration);
}
please suggest me.If user does not select we should show the error message.

The default underlying type of the enumeration elements is int. By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1.
When you are not selecting anything and posting the form, the default value 0 is automatically getting set (default value of integer).
In this case, you can make your property nullable with [Required] attribute which sends null as value when nothing is selected. And as it is decorated with [Required] attribute, it will give you required field validation error.
[Required]
public RegisteredBy? RegisteredBy { get; set; }

Related

Checkbox adds extra "false" value per selected one

I have this piece of code in my View which belongs to a form
<div class="col-md-10">
#foreach (var l in leads)
{
#: #Html.CheckBox("cbLead", false, new { #value = #l.Id }) #Html.TextBox("worth", "") - #Html.Label(l.Name)
}
</div>
And this is the form with I handle the post:
[HttpPost]
public ActionResult Update(string[] cbLead, double[] worth)
{
// code
}
I have 24 checkboxes, but for each checkbox selected I receive 2 values in the Update method. So for example if I select 3 out of that 24 checkboxes, I receive 27 values in the string[] cblead.
Example with 24 checkboxes:
And this is what I get in the method:
So I receive the value checked and an added false after. Any tips?
That's because the Html.CheckBox helper generates an additional hidden field with the same name and the value false. The reason for that is because if the checkbox is not checked, then no value will be sent to the server and thus the model binder will fail to properly bind to a boolean property on your model. Also notice that the Html.CheckBox helper expects that you are working with boolean values on your models. Your syntax here is incorrect:
#Html.CheckBox("cbLead", false, new { #value = #l.Id })
You seem to be trying to manually set the value attribute of the checkbox (which should not be done when using helpers) to the Id property of your model which I suppose is not boolean but rather a Guid as can be seen from the screenshot.
This is by design and is expected behavior. If you do not want this behavior that you could write your own custom helper or use plain HTML instead.
I suspect that what you need to receive on the server is the list of IDs along with a boolean value corresponding to whether the element was checked or not. For this purpose I suggest you writing the following view model:
public class MyViewModel
{
public IList<LeadViewModel> Leads { get; set; }
}
public class LeadViewModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Worth { get; set; }
public bool IsChecked { get; set; }
}
and then:
#for (var i = 0; i < Model.Leads.Count; i++)
{
Html.CheckBoxFor(x => x.Leads[i].IsChecked)
Html.HiddenFor(x => x.Leads[i].Id)
Html.TextBoxFor(x => x.Leads[i].Worth) -
Html.LabelFor(x => x.Leads[i].Name)
}

Dropdownlistfor returns null value

I have a customer class with a property Gender. I created a list of Gender type which contains and id number and Gender type. When form is submitted, I am getting null value.
View
#model MovieRentals.ViewModel.CustomerView
<div class="form-group">
<h4>#Html.LabelFor(l => l.Customer.BirthDate)</h4>
#Html.DropDownListFor(l => l.CustomerGender, new SelectList(Model.CustomerGender, "GenderId", "GenderType"), "Select Gender", new { #class = "form-control" })
</div>
Model
public class CustomerView
{
public IEnumerable<MembershipType> MembershipTypes{ get; set; }
public Customer Customer { get; set; }
public List<GenderClass> CustomerGender{ get; set; }
}
public class GenderClass
{
public int GenderId { get; set; }
public string GenderType { get; set; }
}
Controller
public ActionResult New()
{
var MembershipTy = _context.MemebershipType.ToList();
var ViewModel = new CustomerView();
ViewModel.CustomerGender = new List<GenderClass>()
{
new GenderClass(){ GenderId = 1, GenderType = "Male"},
new GenderClass() { GenderId = 2, GenderType = "Female"}
};
ViewModel.MembershipTypes = MembershipTy;
return View(ViewModel);
}
You need two properties: one to hold the selected value and one to hold the options. The one that holds the options should be IEnumerable<SelectListItem>. Your GenderClass class is completely superfluous.
Also, using an integer id as the value doesn't make sense when the meaning of that value is not obvious. Here, the fact that 1 means Male only exists in the New action. Anywhere else, you will then have to repeat this logic (which introduces opportunities for errors, e.g. was male 1 or 0). Further, if you decide to change those values, you must remember to change them everywhere. If you want to use an integer id, then you should abstract away the meaning somewhere, be it an enum, static class, database table, etc. The far better choice is to just keep it a string, and use the dropdown merely to enforce normalization of that string value.
public string CustomerGender { get; set; }
public IEnumerable<SelectListItem> CustomerGenderChoices
{
get
{
return new List<SelectListItem>
{
new SelectListItem { Value = "Male", Text = "Male" },
new SelectListItem { Value = "Female", Text = "Female" }
}
}
}
Then, in your view:
#Html.DropDownListFor(m => m.CustomerGender, Model.CustomerGenderChoices, "Select Gender", new { #class = "form-control" })
Alternatively, if you were to use an enum:
public enum Genders
{
Male = 1,
Female = 2
}
Then, in your view model, you would only need one property, just to store the value:
public Genders CustomerGender { get; set; }
Then, in your view, you can make use of EnumDropDownListFor:
#Html.EnumDropDownListFor(m => m.CustomerGender, "Select Gender", new { #class = "form-control" })
As an enum, the value stored would be an int, but the benefit here is that you have a strongly-typed association between those integer values and what they mean. For example, rather than doing something like:
if (customer.CustomerGender == 1) // Male
You can do:
if (customer.CustomerGender == Genders.Male)
Obviously, the second version is much more obvious in meaning.

MVC4 annotation conditional validation depending on input of another field

Here is my model:
Primary
{
public Boolean Yes { get; set; }
public Boolean NoHome { get; set; }
public int mailzip
public string mailcity
public string mailstate
}
i have 2 fields based on which required field validation via annotation must be done on a textbox
one of them is a checkbox (condition for required field to activate -> this must be checked)
#Html.CheckBoxFor(model => model.nohome, new { name = "NoHome", id = "NoHome" })
OR
The other is a #Html.RadioButtonFor pair - the below must be clicked as yes for the required field to be validated
#Html.RadioButtonFor(model => model.primary.yes, "true", new { name = "DifferentAddress", id = "DifferentAddressYes" })
#Html.RadioButtonFor(model => model.primary.no, "true", new { name = "DifferentAddress", id = "DifferentAddressYes" })
Either of the above two fields should be able to fire the required field attribute on the below 3 fields
mailzip
mailcity
mailstate

MVC3 cannot validate dropdownfor

Not sure if i'm populating my dropdown correctly but I'm having issue validating the values in my dropdownlist. When a value has been selected it's still showing error 'The value x is invalid'. The type is of int? as I know int doesn't work with the validator.
View model code:
[Display(Name = "Category")]
[Required(ErrorMessage = "Category is required.")]
public AWS.DTO.Lookup Category { get; set; }
public IEnumerable<AWS.DTO.Lookup> Categories { get; set; }
Controller code:
[PageOptions(Title = "Create FMR")]
public ActionResult Create()
{
var model = new FMRRequestViewModel();
model.Categories = new AWS.BL.Lookup().GetFMRCategories();
return View(model);
}
Lookup Type:
public class Lookup
{
public int? ID { get; set; }
public string Description { get; set; }
}
View code:
#Html.DropDownListFor(m => m.Category, new SelectList(Model.Categories, "ID", "Description", -1), "-- Please Select -- ")
Thanks in advance for any help.
DropDown's don't work that way. A dropdown can only send the ID, not the text. You are passing the whole Category object to DropDownListFor, which it won't understand.
#Html.DropDownListFor(m => m.Category.ID, new SelectList(Model.Categories, "ID", "Description", -1), "-- Please Select -- ")
It's not going to bind to a Lookup model once selected. MVC doesn't work like ASP where you receive back an object (ASP you'd "bind" an enumerable of objects and, when selected, the whole object was returned--this is not the case in mvc, only the key will be returned (or whatever property was mapped as the dropdown's value)).
Instead you'd have to accept an Int32 then in your action retrieve the matching Lookup. So, in short:
change your ViewModel so Category is an Int32/int (and not a Lookup object).
in the receiving action map the Lookup based on what Category has for a populated value.

How to clear textboxes defined with MVC HTML helpers

I can't figure out how to do this very simple thing: My page contains a set of textboxes that a user can fill out to add an item to a list. Then the item shows up in a dropdown list.
At that point, I want the "add" textboxes to be cleared. This is the behavior expected by most users, I think. The item has been added; now the textboxes should be empty, ready for the next item to be entered.
However, I can't seem to clear them when I am using Html helpers, e.g., Html.Textbox(...). I like these controls because of the way they "remember" the input in case of input error. However, unlike webforms controls, you can't set them programmatically. They continue to retain the values until the user enters something else.
Is there any way around this behavior? I thought of clearing them in javascript, but I don't want to do that if there are any errors.
UPDATE some of the code;
One of my textboxes in the view:
<h6 style="margin-top: 0px">Add custom email template:</h6>
<div style="margin-top: 10px">
<div class="label">Name:</div>
<%= Html.TextBox("addName", "", new { #class="formtext", style="width: 400px" }) %>
<div class="alerttext"><%= Html.ValidationMessage("addName") %></div>
</div>
The class I am using for model binding:
public class ManageEmailTemplatesSubmittedData
{
[RegularExpression(RegExpressions.templateNameRestrict, ErrorMessage="Names should begin with a character and consist of only characters and numbers")]
public string addName { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage = "Invalid entry; please omit unusual characters")]
public string addDescription { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage = "Invalid entry; please omit unusual characters")]
public string addSubject { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage = "Invalid entry; please omit unusual characters")]
public string addTemplate { get; set; }
public string templates { get; set; }
[RegularExpression(RegExpressions.templateNameRestrict, ErrorMessage = "Names should begin with a character and consist of only characters and numbers")]
public string editName { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage="Invalid entry; please omit unusual characters")]
public string editDescription { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage = "Invalid entry; please omit unusual characters")]
public string editSubject { get; set; }
[RegularExpression(RegExpressions.freeTextRestrict, ErrorMessage = "Invalid entry; please omit unusual characters")]
public string editTemplate { get; set; }
}
My action:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CustomEmails(SubmitButtons buttons, ManageEmailTemplatesSubmittedData data)
{
bool saved = false;
string selectedTemplate = data.templates;
if (ModelState.IsValid)
{
ButtonStyles buttonStyles = ButtonStylesCreator.GetSelectListButtonStyles(rc.persistedData.loggedInUser.userType);
Notification notification = new Notification(rc);
if (buttons.addTemplate == buttonStyles.addEmailTemplateButtonValue)
{
// add an email template
notification.SaveCustomTemplate(data.addName, data.addName, data.addTemplate, data.addSubject, data.addDescription);
saved = true;
}
else if (buttons.saveTemplate == buttonStyles.saveTemplateValue)
{
// update an email template
notification.SaveCustomTemplate(data.templates, data.editName, data.editTemplate, data.editSubject, data.editDescription);
selectedTemplate = "";
saved = true;
}
}
ConfigureEmailsModelBuilder builder = new ConfigureEmailsModelBuilder(rc, rc.persistedData.loggedInUser.userID, selectedTemplate, true, saved);
return View(builder.Build());
}
ConfigureEmailsModelBuilder constructs the view model, which includes a SelectList that is the dropdown list of the items that have been added. (The view is strongly typed to the type generated by builder.Build).
The HTMLHelper's first look at the ModelState and ViewData to see if any values match their key and then finally use whatever value you provide them.
If you need to reset the textboxe's value you also need to clear the ModelState entry with the matching key. Another alternative is redirecting to the same page instead of simply rendering a view via javascript or with MVC.
This is working for me on an MVC3 site log on page.
ModelState.Clear();
model.UserName = string.Empty;
model.Password = string.Empty;
ModelState.AddModelError("", "The user name or password provided is incorrect.");
This will clear the login textboxes used for password and username, and keep any model errors.

Resources