MVC3 Navigation Property Attributes and Client Side Validation - asp.net-mvc-3

I am making my first tentative steps into MVC3 and have come across an issue with the translation of navigation properties within a model to a view. It seems that in the view navigational properties do not allow client side validation nor is the "Display" label attribute picked up.
I have the following simple model:
public class Entity
{
[Key,
ScaffoldColumn(false)]
public int Entity_Id { get; set; }
[Display(Name = "Entity Name"),
Required(ErrorMessage = "Please enter the entity name."),
StringLength(150, ErrorMessage = "Please ensure that the entity name is under 150 characters.")]
public string Entity_Nm { get; set; }
[Display(Name = "Entity Type"),
Required(ErrorMessage="Please select the entity type"),
ForeignKey("EntityType")]
public int EntityType_Id { get; set; }
public virtual EntityType EntityType { get; set; }
}
Which references this model:
public class EntityType
{
[Key]
public int EntityType_Id { get; set; }
[Display(Name = "Entity Name"), Required(ErrorMessage="Please enter the entity type name.")]
public string EntityType_Nm { get; set; }
}
When I create a controller with read/write actions and views for this model I get the following create form:
<fieldset>
<legend>Entity</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Entity_Nm)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Entity_Nm)
#Html.ValidationMessageFor(model => model.Entity_Nm)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.EntityType_Id, "EntityType")
</div>
<div class="editor-field">
#Html.DropDownList("EntityType_Id", String.Empty)
#Html.ValidationMessageFor(model => model.EntityType_Id)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
This is fine apart from the label for the Entity Type drop down, for some reason it is not picking up the "Display" attribute of the navigation property within the model (note the lack of a space). Also client side validation is not enabled for the dropdown list (server side validation works without issue) despite decorating the property with a "Required" attribute. Client side validation works on the other fields. Please note that all the required .js script files have been included and I have also added the relevant enable validation keys to the web.config.
Any ideas what I am missing here? Thanks one and all.

for DropDownList Display issue just try below
#Html.LabelFor(model => model.EntityType_Id)

Related

MVC 5 Conditional Validation Option?

I'm developing an MVC 5 web application. Within a particular View I need to validate a ViewModel, however, I need some of the validation only to occur depending on the users inpupt.
For example, I have a ViewModel
public class TimeEntryViewModel
{
public int proposalID { get; set; }
public int proposalCode { get; set; }
public int nonchargeCode { get; set; }
public SelectList UserProposals { get; set; }
public SelectList TimeEntryClientCodes { get; set; }
public SelectList TimeEntryNonChargeCodes { get; set; }
}
This ViewModel is passed to a View which looks like this
<div class="form-group">
#Html.LabelFor(m => m.proposalID, "Proposal")
#Html.DropDownListFor(m => m.proposalID, Model.UserProposals, "No Proposal", new { #class = "form-control"})
#Html.ValidationMessageFor(m => m.proposalID)
</div>
<div id="ClientCodes" class="form-group" style="display:none">
#Html.LabelFor(m => m.proposalCode, "Client")
#Html.DropDownListFor(m => m.proposalCode, Model.TimeEntryClientCodes, "Select", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.proposalCode)
</div>
<div id="NonChargeCodes" class="form-group">
#Html.LabelFor(m => m.nonchargeCode, "Non Charge")
#Html.DropDownListFor(m => m.nonchargeCode, Model.TimeEntryNonChargeCodes, "Select", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.nonchargeCode)
</div>
If the user selects 'No Proposal' from the first drop down list, then the drop down list 'nonchargeCode' appears and I need to validate so that the user selects an option from it.
However, if the user selects another option from the first down drop list, then the drop down list 'nonchargeCode' will disappear and another drop down called 'proposalCode' will appear. I then want to validate to ensure the user selects an option from this drop down, but not the 'nonchargeCode' (which will be hidden).
In an MVC 4 application I previously coded, I used http://fluentvalidation.codeplex.com/ to help with this scenario.
I'm just wondering if anyone else had used anything else to overcome this problem of conditional validation? If so, I'd be keen to hear.
Thanks again.
You can use conditional validation in jQuery and in fluentvalidation.
You can use a jQuery selector on the validation, something like this.
I'm not sure about the HTML element names.
$( "#myform" ).validate({ rules: {
proposalCode: {
required: "#proposalCode:visible"
} }
Check out jQuery Dependency expression for more information.
In FluentValidation validation (Server side only) you can use the 'When' expression.
RuleFor(r => r.proposalCode).NotNull().When(e => // Check selected value);
Check out the documentation here
I think this should get you started.

Custom error message with DataAnnotationsExtensions

I'm trying to get Scott Kirkland's DataAnnotationsExtensions to work with my MVC4 project. But I'm having problems with the client side validation of an email address. I've added a EmailAddress annotation with a error message, but when I enter an invalid email address I do not get the custom error message, but instead I get the generic email error message "Please enter a valid RecipientEmail address.".
My class looks like this:
public class NpRequest
{
[DisplayName("Telefonnummer som skal overdrages")]
[Required(ErrorMessage = "Angiv telefonnummeret som skal overdrages")]
public string PhoneNumer { get; set; }
[DisplayName("Recipient email address")]
[EmailAddress(ErrorMessage = "This is my custom error message")]
[Required(ErrorMessage = "The recipient email address is required")]
public string RecipientEmail { get; set; }
public RecipientTypeEnum RecipientType { get; set; }
}
And my view:
---SNIPPET BEGIN---
<div class="editor-label">
#Html.LabelFor(model => model.PhoneNumer)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumer)
#Html.ValidationMessageFor(model => model.PhoneNumer)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.RecipientEmail)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.RecipientEmail)
#Html.ValidationMessageFor(model => model.RecipientEmail)
</div>
<p>
<input type="submit" value="Create" />
</p>
---SNIPPET END---
EDIT:
When I inspect the HTML it looks like this:
<input class="text-box single-line input-validation-error" data-val="true" data-val-email="This is my custom error message" data-val-required="The recipient email address is required" id="RecipientEmail" name="RecipientEmail" type="email" value="">
It seems that my custom error message is put into the data-val-email attribute. I was under the impression that the DataAnnotationExtension automatically added my custom error message to the ModelState and thereby also adding it to the field-validation-error span, which is showing the MVC validation error.
Is this assumption wrong? Should I write my own javascript, which extracts the custom error message attribute and injects it into the field-validation-error span?
Can anyone see what I'm doing wrong?
I ended up using a mix of System.ComponentModel.DataAnnotations and DataAnnotationsExtensions. I found out out that most of the time data annotations will also make client side validation. The only time where is no client side validation, is when I check if the phone number is the correct length.
public class NpRequest
{
[DisplayName("Phone number")]
[MinLengthAttribute(8, ErrorMessage = "Phone number must be 8 digits")]
[MaxLengthAttribute(8, ErrorMessage = "Phone number must be 8 digits")]
[DigitsAttribute(ErrorMessage = "Phone number must be 8 digits")]
[Required(ErrorMessage = "Phone number is required")]
public string PhoneNumber { get; set; }
[DisplayName("Modtagers email adresse")]
[EmailAddressAttribute(ErrorMessage = "Invalid email")]
[Required(ErrorMessage = "Email is required")]
public string RecipientEmail { get; set; }
public RecipientTypeEnum RecipientType { get; set; }
}

Issue with TryUpdateModel in MVC3

I have a problem with a TryUpdateModel in MVC3
When the Edit (post) is fired, I have the following code:
public ActionResult Edit(int id, FormCollection collection)
{
var review = FoodDB.FindByID(id);
if (TryUpdateModel(review))
return RedirectToAction("Index");
return View(review);
}
The view is built directly by the VS (so not changed by me)
If I trace the code, I see the new values in FormCollection, but after executing TryUpdateModel, it returns true, doesn't throw any error, but the review object isn't updated.
What could I do wrong?
EDIT
I come up with some more details:
First, the db is not real DB, but just a "simulation" - class with one static genric List
List<Review> Review;
Review class is simply a POCO, as below:
public class Review
{
public string Message { get; set; }
public DateTime Created { get; set; }
public int ID { get; set; }
public int Rating { get; set; }
}
The view is strong-typed, generated by VS from the Edit method of the controller. Fields are defined as below:
<div class="editor-label">
#Html.LabelFor(model => model.Message)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Message)
#Html.ValidationMessageFor(model => model.Message)
</div>
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Rating)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Rating)
#Html.ValidationMessageFor(model => model.Rating)
</div>
Call to var review = FoodDB.FindByID(id); returns Review object
Even if TryUpdateModel(review) does not work (I trace through code, and I inspected review object before and after the call, as well as the collection, and it receives correct values), yet the review obj is not updated.
However, I replaced it with my own hand-written method, as below, and in this case the review object DOES get updated:
private void MyTryUpdateModel(Review review, FormCollection collection)
{
review.Message = collection["Message"];
review.Rating = int.Parse(collection["Rating"]);
}
So the TryUpdateMethod SHOULD find proper fields in collection for updating, as I understand.
So, what can be wrong?
Thanks all
Based on the code you posted, the review object is not updated, because the new values in FormCollection have not been bound to your model. You are not using the DefaultModelBinder.
If your view is strongly typed (and assuming the type class is named Food), change your method signature and method as follows:
public ActionResult Edit(Food food)
{
if (ModelState.IsValid)
{
FoodDB.Update(food);
return RedirectToAction("Index");
}
return View(food);
}
The DefaultModelBinder will take the values from the form and bind them to your model.

ASP.Net MVC3 Email/Phone Data Annotations don't work

I have the following properties in my Model
[Required]
[DataType(DataType.PhoneNumber, ErrorMessage = "Invalid Phone Number")]
public string PhoneNumber
{
get;
set;
}
[Required]
[DataType(DataType.EmailAddress, ErrorMessage = "Invalid Email Address")]
public string EmailAddress
{
get;
set;
}
The corresponding View is
<td>
Email
</td>
<td>
#Html.EditorFor(model => model.EmailAddress)
#Html.ValidationMessageFor(model => model.EmailAddress, "*")
</td>
</tr>
<tr>
<td>
Phone #
</td>
<td>
#Html.TextBoxFor(model => model.PhoneNumber)
#Html.ValidationMessageFor(model => model.PhoneNumber, "*")
</td>
When I render this page I see the Required attribute getting triggered. But the DataType attribute is not getting fired if I key in Invalid data.I see the source html and don't see any code being emitted for these validations.
I have the following as a part of my view too
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"/>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"/>
You could consider using ASP.NET MVC 3 Futures. Here is a nice article describing validations there:
public class UserInformation
{
[Required]
public string Name { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
[Url]
public string Website { get; set; }
[Required]
[CreditCard]
public string CreditCard { get; set; }
[Required]
[FileExtensions(Extensions = "jpg,jpeg")]
public string Image { get; set; }
}
See this post:
Is the DataTypeAttribute validation working in MVC2?
It's important to note that the DataType Attribute is usually used for formatting purposes, not for validation. Technically there are a wide range of email formats and phone number formats (see here for email: http://www.regular-expressions.info/email.html).
Also, custom converters can be made to convert seemingly non-email strings into emails (me at domain dot com = me#domain.com), and thus having default validation regexs flies out the window. It is left up to the developer to use the correct regex for their specific purpose, and to ensure they only accept address they believe are accurate.
Related to this question, there are some third party data validation annotations for download at http://dataannotationsextensions.org/
I just had a similar issue myself. I had the model setup with a data type of email but it was not being validated as an email. I noticed in the html that the view produced the textbox for the email address had a type of text. I then altered my view as below and this fixed it:
#Html.TextBoxFor(m => m.Email, new { type = "email" })
the was using the jquery validate javascript libary

client side validation for asp.net mvc dropdown?

i just wanted to know how to enable client side validations for dropdowns in asp.net mvc 2.
The scenario would be that the dropdown will contain a "Select" item and the list of other items..,The user should select other items... the validation should fire when the user does not select the other items
public class FacilityBulletinModel
{
[DisplayName("Select a Facility")]
public List<SelectListItem> ListFacility { get; set; }
[DisplayName("Facility Bulletin")]
[Required(ErrorMessage = "Please create a Bulletin")]
public string FacilityBulletin { get; set; }
[DisplayName("Active")]
public bool Active { get; set; }
[HiddenInput(DisplayValue = false)]
public int SiteId { get;set;}
}
in my view
Select Facility <span class="err">*</span><br />
<%=Html.DropDownListFor(model => model.ListFacility, null, new {onChange="updateSiteId()" })%>
<span class="err"> <%= Html.ValidationMessageFor(model => model.ListFacility) %></span>
First, if a dropdown is required, add the [Required] attribute to your model property.
Then, enable client side validation somewhere at the top of your view:
<% Html.EnableClientValidation() %>
Then just add a validation message:
<div class="inputField">
<%= Html.LabelFor(model => model.property)%>
<%= Html.DropDownListFor(model => model.property, (SelectList)ViewData["myselelectlist"])%>
<%= Html.ValidationMessageFor(model => model.property)%>
</div>
(this requries MicrosoftMvcValidation.js to be loaded)

Resources