MVC4 annotation conditional validation depending on input of another field - asp.net-mvc

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

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.

How to set default value to empty EditorFor-field when post a form i .NET MVC

I have a form in .NET MVC 5. where the user can write a number, default is "0", If the user deletes a number e.g. "233" an leaving the field empty. The form would not submit.
How can I submit the form with an empty field?
public class myModel
{
public int nummer { get; set; }
public myModel(){}
public myModel(int i) {this.nummer = i;}
}
razor code:
using (Html.BeginForm("myAction", "myController", FormMethod.Post, new { #class = "form-inline" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text- danger" })
#Html.EditorFor(model => model.nummer, new { htmlAttributes = new { #class = "form-control " } })
<input type="submit" value="submit" name="btnSubmit"/>
}
I am not interested in a validation error message, but to have the value set to "0", by default.
The DefaultModelBinder initializes your model using the parameterless constructor (your second constructor is never called). You will need to make the property nullable to prevent client and server side validation errors
public int? nummer { get; set; }
and then in the POST method, test for null and if so, set the value to 0
if(!model.nummer.HasValue)
{
model.nummer = 0;
}
Alternatively you could write your own ModelBinder that tests for a null value and in the ModelBinder, set the value to 0
You will need to set your nummer field to be a nullable type, like so:
public class myModel
{
public int? nummer { get; set; }
...
}
This will allow a user to submit the form without a value entered.
Then within your controller action you will need to assign a default value if the field is null:
if (model.nummer == null) model.nummer = 0;
Alternatively, you could use a private property like so:
public class myModel
{
private int? privateNummer { get; set; }
public int? nummer
{
get { return this.privateNummer == null ? 0 : this.privateNummer; }
set
{
this.privateNummer = value;
}
}
}
in your controller before passing the model back to the view do this ..
model.find(id);
model.nummer =0;
return View(model)

mvc enum radio button required field

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; }

DropDownListFor(...) selecting boolean false by default

I have typical YesNo kind of dropdown in the application. For that, I have developed model (rather ViewModel Utility) class for future extension prupose.
public string Text { get; set; } // represents text part
public bool Value { get; set; } // represent value
public List<DropDown> DropDowns { get; set; } //list for binding
public void BuildYesNoDropDown()
{
DropDowns = new List<DropDown>();
DropDowns.Add(new DropDown { Text = "Yes", Value = true });
DropDowns.Add(new DropDown { Text = "No", Value = false });
}
Then, I bind it in view like following:
#Html.DropDownListFor(x => x.SelectedValue, new SelectList(Model.DropDowns, "Value", "Text",1),"Select") //last para - OptionLabel
On the view, all three parameters are getting display i.e. "Select", "Yes" and "No". But, by default "No" has been selected. If I make "Value" property as integer then it works fine and by default "Select" gets selected, but as mentioned in the code, if I tend to go with bool type then "No" gets selected.
How to get normal behavior when DataValueField is bool?
ViewModel
public bool flag { get; set; }
View
#Html.DropDownListFor(model => model.flag, new List<SelectListItem>()
{
new SelectListItem() { Text = "Yes", Value = "True" },
new SelectListItem() { Text = "No", Value = "False"}
}, "Select.....", new { #id = "flag", #class="form-control" })
#Html.ValidationMessageFor(model => model.flag)
Model:
public bool? Value { get; set; }
View:
#Html.EditorFor(model => model.Value)
This makes a drop down list automatically with 3 states that match the 3 states of a nullable bool: null, true, false. If you require that Value be answered you can use data annotations like so:
Model:
[Required]
public bool? Value { get; set; }
The takeaway is your model needs to be a real model -- it needs to model the input values from unset to set. If you need to input a int, you'll likely want to use a nullable int (so int?) and require the value. That way the initial value is null instead of 0. It is similar with other data types except string which is already nullable.
In my case I had a bunch of these dropdowns on the same page and I thought I'd be clever and reuse the select list, e.g.
var YesOrNoTriState = new List<SelectListItem> {
new SelectListItem { Text = "Select", Value = "" },
new SelectListItem { Text = "Yes", Value = true.ToString() },
new SelectListItem { Text = "No", Value = false.ToString() }
};
and in the view
<%: Html.DropDownListFor(x => x.Field1, Model.YesOrNoTriState) %>
<%: Html.DropDownListFor(x => x.Field2, Model.YesOrNoTriState) %>
that wasn't working. I initialized a separate select list for each dropdown and that fixed the problem
I know this is a old topic but I thought that for others this might come in handy to know a little background about.
no is selected by default because the default value of a bool is false
if you just set the model to be a
null-able Bool like this in your view model then it should by default select your default value. :
public bool? Value { get; set; }
and then you just set your dropdownlist like this in the view:
#Html.DropDownListFor(x => x.SelectedValue, new SelectList(Model.DropDowns, "Value", "Text",1),"{Default Select Value}")
the result of this should be that when the bool is null the automatically selected option should be your default value {Default Select Value}

Resources