MVC Why is this dropdown mandatory? - asp.net-mvc

I have this dropdown in my view (actually I have many of these in a loop)
#Html.DropDownListFor(m => m.SelectedAttributeValueIds[i], Model.AttributeValuesList[Convert.ToInt32(type.Value)], "Select a value")
The relevant parts of the model are
public IDictionary<int, List<SelectListItem>> AttributeValuesList { get; set; }
public List<int> SelectedAttributeValueIds { get; set; }
The dropdowns above contains the correct list of values. If I select one of the values and submit then the value selected is correctly posted and correctly saved into the SelectedAttributeValueIds list.
Now the problem is that if I do not select a value from one or more of these dropdowns my ModelState.IsValid is false in my post action method. Looking at the error list, the reason is that
"a value is required"
Why are the dropdowns mandatory? I'd like them to be optional.
Any ideas?
Thanks,
Sachin

Maybe it is because you use [Required] attribute in Model, if not you can change the property type to nullable one :
public List<int?> SelectedAttributeValueIds { get; set; }

This is because the SelectedAttributeValueIds property is a list of ints that have an implicit value. If you want it to have no value, change the type to a nullable int using List<int?>.
If you really want to leave it as int you can set DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes to false in your Global.asax I'd recommend using the int? however.

Related

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.

ASP.NET MVC optional field being treated as required

I have this field that for some reason when I click on submit, gets a validation message that the field is required.
[DisplayName("Total Budget:")]
public double Budget { get; set; }
#Html.EditorFor(model => model.account.Budget)
#Html.ValidationMessageFor(model => model.account.Budget)
public class Account
{
[DisplayName("Total Budget:")]
public double Budget { get; set; } //dropdown
}
The built-in DefaultModelBinder in MVC will perform required and data type validation on value types like int, DateTime, decimal, etc. This will happen even if you don't explicitly specify validation using someting like [Required].
In order to make this optional, you will have to define it as nullable:
public double? Budget { get; set; }
You have to add the following line in the application_start (global.asax)
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Source: Unrequired property keeps getting data-val-required attribute
double is a value type. Value types always contain a value, even if you did not set one. That value is the default value for it's type (in this case 0.0). All value types are treated as required by the framework. The only way around this is to create a custom model binder, but that will not prevent the model from containing the default value (because there is no way to say that it wasn't entered).
So even if you create a custom binder, when you process your model, you won't be able to tell if someone entered 0 or whether that was just the default value.
Thus, the only real solution is to change your view model to use a nullable type, such as Nullable<double> (shorthand is double?).
You probably change Budget from a double to double?
You probably can try adding this attribute to the controller
BindExclude([Bind(Exclude="Budget")]) as well
Use Nullable or ? after attribute name.
Use [NotMapped] annotation , this removes the required validation in the flow you also use own display attributes
I have just encountered the problem with a project migrated to .Net 6.0, suddenly some fields started to be required even if there's no data annotation for it.
For example, in
public class LoginModel
{
[BindProperty]
public InputModel Input { get; set; }
[TempData]
public string ErrorMessage { get; set; }
...
}
I got the error : "The ErrorMessage field is required", which have of course no sense at all.
The project has <Nullable>enable</Nullable> feature enabled, it seem to cause this.
Simply rewrite property to
public string? ErrorMessage { get; set; }
To fix this (note the question mark)
You may also use:
services.AddControllers(options => options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true);

DropDownListFor() bindling value AND text to viewmodel

I have a form on a View with a dropdown list, implemented with DropDownListFor(). This View is strongly typed to a ViewModel, which has a SelectList property to hold the options of the dropdown, and then another property to hold the selected value of the dropdown. This is working fine, but what I'd like to do is, hold both the selected value AND selected text of the dropdown in my second property. The reason I want to do this is so that as the form selfposts, I have both the text and value of each selection.
I tried changing the selected value property from an int to a KeyValuePair but only the int part of the pair is set on form submission.
Perhaps there is a better way altogether to accomplish this, I am open to all suggestions including a partial redesign of my methods.
Controller (building SelectList)
SelectList leadTypeGroups = new SelectList(_enrollmentRepository.GetLeadTypeGroups(), "Key", "Value");
ViewModel
public KeyValuePair<int, string> LeadTypeGroupID { get; set; }
public SelectList LeadTypeGroups { get; set; }
View
#Html.DropDownListFor(selected => Model.LeadTypeGroupID, Model.LeadTypeGroups, " ")
Have the sever pull the values from the database (or an in-memory cache) on each request. Alternatively, have a hidden field with javascript that updates it with the appropriate text whenever the dropdown selection changes.
Change the ViewModel to a List and then use a for loop to spit out a drop down for each item in the list. Something like...
View
#for( int i = 0; i < Model.LeadTypeGroupIDs; i++ )
{
#Html.DropDownListFor(x => Model.LeadTypeGroupIDs[i], Model.LeadTypeGroups, " ")
}
ViewModel
public List<string> LeadTypeGroupIDs { get; set; }
public SelectList LeadTypeGroups { get; set; }

ASP.NET MVC 2 "value" in IsValid override in DataAnnotation attribute passed is null, when incorrect date is submitted

This is my first question here on stack overflow.
i need help on a problem i encountered during an ASP.NET MVC2 project i am currently working on.
I should note that I'm relatively new to MVC design, so pls bear my ignorance.
Here goes :
I have a regular form on which various details about a person are shown. One of them is "Date of Birth". My view is like this
<div class="form-items">
<%: Html.Label("DateOfBirth", "Date of Birth:") %>
<%: Html.EditorFor(m => m.DateOfBirth) %>
<%: Html.ValidationMessageFor(m => m.DateOfBirth) %>
</div>
I'm using an editor template i found, to show only the date correctly :
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime?>"%>
<%= Html.TextBox("", (Model.HasValue ? Model.Value.ToShortDateString() : string.Empty))%>
I used LinqToSql designer to create my model from an sql database. In order to do some validation i made a partial class Person to extend the one created by the designer (under the same namespace) :
[MetadataType(typeof(IPerson))]
public partial class Person : IPerson
{ //To create buddy class }
public interface IPerson
{
[Required(ErrorMessage="Please enter a name")]
string Name { get; set; }
[Required(ErrorMessage="Please enter a surname")]
string Surname { get; set; }
[Birthday]
DateTime? DateOfBirth { get; set; }
[Email(ErrorMessage="Please enter a valid email")]
string Email { get; set; }
}
I want to make sure that a correct date is entered. So i created a custom DataAnnotation attribute in order to validate the date :
public class BirthdayAttribute : ValidationAttribute
{
private const string _errorMessage = "Please enter a valid date";
public BirthdayAttribute() : base(_errorMessage) { }
public override bool IsValid(object value)
{
if (value == null)
{
return true;
}
DateTime temp;
bool result = DateTime.TryParse(value.ToString(), out temp);
return result;
}
}
Well, my problem is this. Once i enter an incorrect date in the DateOfBirth field then no custom message is displayed even if use the attribute like [Birthday(ErrorMessage=".....")]. The message displayed is the one returned from the db ie "The value '32/4/1967' is not valid for DateOfBirth.". I tried to enter some break points around the code, and found out that the "value" in attribute is always null when the date is incorrect, but always gets a value if the date is in correct format. The same ( value == null) is passed also in the code generated by the designer.
This thing is driving me nuts. Please can anyone help me deal with this?
Also if someone can tell me where exactly is the point of entry from the view to the database. Is it related to the model binder? because i wanted to check exactly what value is passed once i press the "submit" button.
Thank you.
Generally speaking all validation stuff is work after binder binded values. As you can understand it's not possible to bind dateTime value from string like "asdvfvk". So, when binder encounters with such an error it adds it to the ModelState (take a look at ModelState["DateOfBirth"].Errors[0].ErrorMessage), and binds default value. Default value for DateTime? is null, so that's why you always get it in IsValid method. It's normal.
So as you can see validation for date has sence if you whant to check for example if it's bigger then some other date. If input string is incorrect no further verification have sence.
What can you do?
First straightforward way - you can correct your action like this
[HttpPost]
public ActionResult About(Person person, string dateOfBirth) {
var birthdayAttribute = new BirthdayAttribute();
if( !birthdayAttribute.IsValid(dateOfBirth)) {
ModelState["DateOfBirth"].Errors.Clear();
ModelState.AddModelError("DateOfBirth", birthdayAttribute.ErrorMessage);
}
.......
}
As you can see there is string dateOfBirth, so binder have no problems with binding string value. But this will not make your users happy.
The better way - ensure that string will be in correct format with client Javascript. Actualy people use date picker controls for dates and feel themselves good.
In addition take a look here http://forums.asp.net/t/1512140.aspx
Especialy Brad Wilson's answer.

problem with dropdownlist in mvc application

I am trying to work with an HTML.DropDownList in MVC and am not getting the expected return values. Here is my implementation for the selectList to bind to the drop down -
IEnumerable<status> stat = _provider.GetAllStatuses();
Statuses = new SelectList(stat.ToList(), "id", "name", i.status.id);
And here is my view -
<%= Html.DropDownList("Status",Model.Statuses) %>
I am getting an error when trying to run updatemodel in my controller. I then tried to individually set each object. It turns out that I am not getting a single int from the formvalue as I would expect to. Instead, I am getting a value like "5,10,2,3". I think this is coming from how I set up my selectlist, but I'm not exactly sure. Can anyone see an error in the way I am setting up this dd?
Thanks for any help, and let me know if I can clarify anything.
What does the signature of the post method look like? It (or the model) should have a Status property that's defined as an int. I suspect that you've got more code than you're showing us that is listing all the potential statuses on the page (hidden fields?) and that's what you are seeing posted back as an array of ints.
It should look something like:
public ActionResult PostAction( int status, .... )
{
... status will contain the selected value from the dropdown ...
}
This is how I am doing it:
var stat = _provider.GetAllStatuses();
myViewDataObject.Statuses = new SelectList(stat, "id", "name", i.status.id);
stat is an IEnumerable. Statuses is of type SelectList. You don't need ToList() if you are returning an IEnumerable or IQueryable from your provider.
My view inherits from
System.Web.Mvc.Viewpage<MyProject.Models.MyViewDataClass>
which looks like this:
class MyViewDataClass
{
public int StatusID { get; set; }
public SelectList Statuses { get; set; }
}
In the controller, I am accepting a FormsCollection object, and using the model binder to update it:
public ActionResult Edit(FormCollection collection)
{
var myViewDataObject = new MyViewDataClass();
UpdateModel(myViewDataObject);
}
More info at http://nerddinnerbook.s3.amazonaws.com/Part6.htm

Resources