I am having an issue with ASP.NET MVC3 client side validation.
My view is based on a viewmodel I've created with the following fields as Required
public class AppointmentFeedbackViewModel_Validation
{
[Required]
public string AttendeeName { get; set; }
[Required(ErrorMessage = "Notes must be filled in")]
public string Notes { get; set; }
[Required(ErrorMessage = "Appointment status must be filled in")]
public int AppointmentStatusId { get; set; }
[Required]
public int StarId { get; set; }
}
Unfortunately, a completely unrelated field SubStatusId appears as required on submitting the form.
This drop down list is passed an empty List from the controller
new List<EF.ViewModels.OpportunityConnectTypeViewModel>();
and marked up as below
<div class="display-label-styled">
Please select another reason for this outcome
</div>
<div class="display-field-styled">
#Html.DropDownListFor(model => model.SubStatusId, new SelectList(ViewBag.SubStatus, "ID", "StatusName"))
#Html.ValidationMessageFor(model => model.SubStatusId)
</div>
If anybody can shed any light on this for me, I'd really appreciate it.
Is SubStatusId an int? Int's are implicitly required. If you want it to not be required, declare it as a nullable int:
public int? SubStatusId;
Related
Im beginer for the MVC , Im develop the MVC project i have a some dropdown menu, i want to remove client slide validation how can i do it. i was removed but not work
<div class="col-md-3">
#Html.DropDownListFor(a => a.Ach, new SelectList(ViewBag.AtList4, "AtId", "AName"), " Select a A", new { Class = "form-control dd", title = "aa", style = "width:175px;height:30px; margin-top:6px;font-size:small;" })
#Html.ValidationMessageFor(a => a.Ach)
</div>
model
[Key]
public int ItemTemplateId { get; set; }
[ForeignKey("MainGroup")]
public int MainGroupId { get; set; }
public virtual MainGroup MainGroup { get; set; }
[Required(ErrorMessage = "Required")]
[ForeignKey("SubGruop")]
public int SubGruopId { get; set; }
public virtual SubGroup SubGruop { get; set; }
public int Ach { get; set; }
Change the property Ach to a nullable int and then no value will be acceptable:
public int? Ach { get; set; }
I anticipate that setting this value to nullable isn't acceptable, because you don't want null values for the property within your database. Keep reading...
I notice that your View Model has [Key], [ForeignKey] and virtual properties, which suggests to me that you're using your domain models as view models.
You should really have a whole new class that has a specific use as a View Model for your page that contains the minimum number of properties to hold only the values that are required to display the view.
I have a simple table with a non-nullable date field. The field has a default value of GetDate() in the DB.
The DB table is brought forward via EntityFramework,
When I let the MVC 4 templates auto-generate a create.cshtml page for that table it works but when I try to run that table I get the error:
The model item passed into the dictionary is null, but this dictionary requires a non-null model item of type 'System.DateTime'.
CSHTML file:
#model MyModel.Content
<div class="editor-label">
#Html.LabelFor(model => model.ActiveDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ActiveDate)
#Html.ValidationMessageFor(model => model.ActiveDate)
</div>
The EF auto-generated class:
public partial class Content
{
public int ID { get; set; }
public string Title { get; set; }
public int CategoryID { get; set; }
public string Content1 { get; set; }
public bool IsActive { get; set; }
public System.DateTime ActiveDate { get; set; }
public System.DateTime DeactiveDate { get; set; }
public System.DateTime LastEditDate { get; set; }
public string LastEditor { get; set; }
public virtual ContentCategory ContentCategory { get; set; }
}
This doesn't seem like that unusual of a way to do this. Shouldn't the templates be able to deal with creating a new non-nullable date?
What must I do to get around this?
The way I deal with this is to use nullable DateTimes on my viewmodel and set the [Required] attribute on them, so that if the model validates, then I can guarantee when I copy the values to my entity model and save the data, then it will succeed. This way you can keep your entity model(what is saved to the database) as a non-null datetime.
The other option is to provide a default value for the datetime if there is something sensible, based on other data or based on current datetime. For example, defaulting ActiveDate to the current date, so that by default it begins to be active now.
Otherwise the first option is the best, because you don't want to provide a nonsensical default like 1/1/0001
I have the following code-
View-
<% Html.BeginForm(); %>
<div>
<%= Html.DropDownList("DropDownSelectList", new SelectList( Model.DropDownSelectList, "Value", "Text"))%>
Controller-
public ActionResult Admin(string apiKey, string userId)
{
ChallengesAdminViewModel vm = new ChallengesAdminViewModel();
vm.ApiKey = apiKey;
vm.UserId = userId;
vm.DropDownSelectList = new List<SelectListItem>();
vm.DropDownSelectList.Add(listItem1);
vm.DropDownSelectList.Add(listItem2);
vm.DropDownSelectList.Add(listItem3);
vm.DropDownSelectList.Add(listItem4);
vm.DropDownSelectList.Add(listItem5);
vm.DropDownSelectList.Add(listItem6);
vm.DropDownSelectList.Add(listItem7);
}
[HttpPost]
public ActionResult Admin(ChallengesAdminViewModel vm)
{
if (ModelState.IsValid)//Due to the null dropdownlist gives model state invalid
{
}
}
ViewModel-
public class ChallengesAdminViewModel
{
[Required]
public string ApiKey { get; set; }
[Required]
public string UserId { get; set; }
public List<SelectListItem> DropDownSelectList { get; set; }
}
I dont know why it still requires the list although not required. I want to have only two attributes as required. So I wanted to know how do i declare or change that list to be not required and have my Model State Valid.
The way I do it is have a property in my view model that the dropdown will be bound to (which is nullable) and then have a separate property that contains all the options for the drop down.
ViewModel properties
public int? CountryId { get; set; }
public IEnumerable<SelectListItem> CountryOptions { get; set; }
View
<label for="CountryId">Country:</label>
<%: Html.DropDownListFor(x => x.CountryId, Model.CountryOptions, "N/A")%>
Note: The "N/A" string is the default empty value.
HTHs,
Charles
Ps. This is of course using ASP.NET MVC 2
The simple answer would be to remove it from your model and pass it via ViewData instead. Then, your model would contain a member for the value that was selected from the list.
I think it's failing because it can't coerce a single value ("") into a SelectListItem to put into a list. You can only ever have one DropDownSelectList value selected.
You might try making your ChallengesAdminViewModel.DropDownSelectList of type string instead. Then it will be the value of the selected option. SelectListItems are made for pushing options to the view, not parsing the posted result.
I have some interface and classes
public inteface IRole
{
int Id { get; }
string Name { get; set; }
}
public class Role : IRole
{
public int Id { get; }
[Display("Role Name")]
public string Name { get; set; }
}
public class Member
{
[Display("Login")]
public string Login { get; set; }
[Display("Password")]
public string Password { get; set; }
public IRole Role { get; set; }
}
on View I try to use, View is strongly type of Member
on this line displays correct message from DisplayAttribute
<%= Html.LabelFor(m => m.Login) %>
on this line it does not display correct label from DisplayAttribute
<%= Html.LabelFor(m => m.Role.Name) %>
How can I fix this to have correct labels in such architecture?
Thanks
P.S. I know about adding DisplayAttribute to the interface field and all will work, but maybe there are different solution.
Everything is working as designed here.
You already know your answer. If you display a form for IRole you must also have the attributes on IRole.
In order to have the correct labels you'd have to implement your own TypeDescriptors or ModelMetadataProvider in order to "smush" together the metadata for an interface into any concrete classes that implement them.
This will become really complex real fast.
Why can't you just add the attribute to the IRole interface?
Inherited properties and MetadataType does not seem to work with client side validation in ASP.NET MVC 2.
The validation of our MetadataTypes work as expected on the server but for some reason it does not generate the appropriate client scripts for it. Client side validation kicks in as expected for properties with the DataAnnotations attributes set on the PersonView so I know that client side validation is active and that it works. Does anyone know if or how it can be fixed?
Here's what we have:
public abstract class PersonView
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
[Required] public string PhoneNumber { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressZipCode { get; set; }
public string AddressCity { get; set; }
public string AddressCountry { get; set; }
}
[MetadataType(typeof(CustomerViewMetaData))]
public class CustomerView : PersonView {}
[MetadataType(typeof(GuestViewMetaData))]
public class GuestView : PersonView {}
public class GuestViewMetaData
{
[Required(ErrorMessage = "The guests firstname is required")] public string FirstName { get; set; }
[Required(ErrorMessage = "The guests lastname is required")] public string LastName { get; set; }
}
public class CustomerViewMetaData
{
[Required(ErrorMessage = "The customers firstname is required")] public string FirstName { get; set; }
[Required(ErrorMessage = "The customers lastname is required")] public string LastName { get; set; }
[Required(ErrorMessage = "The customers emails is required")] public string Email { get; set; }
}
As you can see, it's nothing fancy or strange in there... Can it be fixed? Is it a bug in ASP.NET MVC 2?
According to a Microsoft official this is a bug in ASP.NET MVC 2. I was given the link below and although the scenario isn't exactly the same, it seems to be the same problem. As far as I can tell it is related to inhertited properties and DataAnnotations model metadata provider. The link says they will try to fix the issue in ASP.NET MVC 3.
Asp.net MVC 2 RC2: the client side validation does not work with overridden properties
Maybe it's too late but this is the way I managed to solve this bug.
I've created a custom model metadata provider that inherits from DataAnnotationsModelMetadataProvider and override the CreateMetadata method.
The problem is that the value in containerType parameter points to the base class instead of pointing to inherited class.
Here is the code
public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(
IEnumerable<Attribute> attributes,
Type containerType,
Func<object> modelAccessor,
Type modelType,
string propertyName)
{
if (modelAccessor != null && containerType != null)
{
FieldInfo container = modelAccessor.Target.GetType().GetField("container");
if (containerType.IsAssignableFrom(container.FieldType))
containerType = container.FieldType;
}
var modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
return modelMetadata;
}
}
And finally we have to register this custom metadata provider in Global.asax at Application_Start
ModelMetadataProviders.Current = new CustomModelMetadataProvider();
Sorry for my English!
Are you sure? I've got a ASP.NET MVC 2 site set up as you describe and I have client side validation of both required and regex based attributes that works fine. It doesn't work with my own validators (that derive from ValidationAttribute) at the moment though:
[MetadataType(typeof(AlbumMetadata))]
public partial class Album {}
public class AlbumMetadata {
[Required(ErrorMessage = "You must supply a caption that is at least 3 characters long.")]
[MinLength(3, ErrorMessage = "The caption must be at least {0} characters long.")]
[RegularExpression(#".{3,}")]
public string Caption { get; set; }
}
(MinLength basically provides a more obvious way to see what's happening in the Regular Expression attribute, which was added for testing)
I then have the following in my view:
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcValidation.js" type="text/javascript"></script>
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Album details</legend>
<div class="form_row">
<label for="Caption" class="left_label">Album caption:</label>
<%= Html.TextBox("Caption", Model.Caption, new { #class = "textbox" })%>
<%= Html.ValidationMessage("Caption", "*") %>
<div class="cleaner"> </div>
</div>
<div class="form_row">
<label for="IsPublic" class="left_label">Is this album public:</label>
<%= Html.CheckBox("IsPublic", Model.IsPublic) %>
</div>
<div class="form_row">
<input type="submit" value="Save" />
</div>
</fieldset>
<% } %>
Which results in the following being output to the client below the form tags (formatted for clarity):
<script type="text/javascript">
//<![CDATA[
if (!window.mvcClientValidationMetadata)
{ window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({
"Fields":[
{"FieldName":"Caption",
"ReplaceValidationMessageContents":false,
"ValidationMessageId":"Caption_validationMessage",
"ValidationRules":[
{"ErrorMessage":"You must supply a caption that is at least 3 characters long.",
"ValidationParameters":{},
"ValidationType":"required"},
{"ErrorMessage":"The field Caption must match the regular expression \u0027.{3,}\u0027.",
"ValidationParameters":{"pattern":".{3,}"},
"ValidationType":"regularExpression"}]
}],
"FormId":"form0","ReplaceValidationSummary":false});
//]]>
</script>