MVC 3 Validation - Only show error messages after lost focus or submit? - validation

I have setup the entities in my MVC 3 app with DataAnnotations (required, stringlength, etc) and the MVC page is showing validation error messages appropriately. But, the error messages are shown as soon as the page loads on a new form before the user has had the chance to enter an invalid value.
I had used JQuery validation a few years ago and was able to only show the error messages after the user lost focus on a field or attempted to submit the form. In fact, I think it was the default behavior.
Is there anyway to do the same in MVC 3 using DataAnnotations?
EDIT: Here is the HTML
<div class="form horizontal floated w50p">
<h3>Billing Information</h3>
#using(Html.BeginForm()){
<div class="item">
<div class="label">
<label>* First Name</label></div>
<div class="value">#Html.TextBoxFor(x => x.Name)</div>
<div class="value">#Html.ValidationMessageFor(x => x.Name)</div>
</div>
<div class="item">
<div class="label">
<label>* Address 1</label></div>
<div class="value">#Html.TextBoxFor(x => x.Street1)</div>
<div class="value">#Html.ValidationMessageFor(x => x.Street1)</div>
</div>
<div class="item">
<div class="label">
<label>Address 2</label></div>
<div class="value">#Html.TextBoxFor(x => x.Street2)</div>
</div>
<div class="item">
<div class="label">
<label>Address 3</label></div>
<div class="value">#Html.TextBoxFor(x => x.Street3)</div>
</div>
<div class="item">
<div class="label">
<label>City</label></div>
<div class="value">#Html.TextBoxFor(x => x.City)</div>
<div class="value">#Html.ValidationMessageFor(x => x.City)</div>
</div>
<div class="item">
<div class="label">
<label>State/Province/Region</label></div>
<div class="value">#Html.TextBoxFor(x => x.StateProv)</div>
<div class="value">#Html.ValidationMessageFor(x => x.StateProv)</div>
</div>
<div class="item">
<div class="label">
<label>Zip / Postal Code</label></div>
<div class="value">#Html.TextBoxFor(x => x.PostalCode)</div>
<div class="value">#Html.ValidationMessageFor(x => x.PostalCode)</div>
</div>
<div class="item">
<div class="label">
<label>* Contact Phone</label></div>
<div class="value">#Html.TextBoxFor(x => x.ContactPhone)</div>
<div class="value">#Html.ValidationMessageFor(x => x.ContactPhone)</div>
</div> <input type="submit" value="Submit" />
}

The default behavior is exactly what you describe (errors should appear only after a field loses focus or form is submitted). So, there must be something wrong with your view or controller. Specifically, it sounds like the validator thinks the user is posting back even on the first view of the form. The first view of the form should be a GET not a POST. If you paste your controller code, that might help us diagnose it better.

You mean like enabling client validation? Sure, that's easy. Just:
create a view model
decorate it
create controller
create a view
include proper jquery scripts
So let's go ahead and follow those steps.
View model:
public class ProductViewModel
{
[Required] // <-- you could use any data annotation attributes you like
public string Name { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new ProductViewModel();
return View(model);
}
[HttpPost]
public ActionResult Index(ProductViewModel model)
{
return View(model);
}
}
View:
#model ProductViewModel
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.LabelFor(x => x.Name)
#Html.EditorFor(x => x.Name)
#Html.ValidationMessageFor(x => x.Name)
<input type="search" value="OK" />
}
Now leave the field blank and client validation will trigger assuming it is enabled in web.config (which it is by default when you create a new ASP.NET MVC 3 project using the default Visual Studio template):
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
If you want to handle custom validation attributes you could but it might be a little more painful. And once you get yourself confronted to real world applications and realize the weaknesses of declarative validation using attributes (data annotations) I would strongly recommend you checking out FluentValidation.NET.

Related

required attribute not generating in mvc partial razor view (using Edmx Models)

#model eDurar.Models.BuyOnlineAddress
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>BuyOnlineAddress</legend>
<div class="editor-label">
Address Details
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Details, new {#required="required" })
#Html.ValidationMessageFor(model => model.Details)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
This is partial view, in the html generated, there is no required attribute
When I manually insert it in the html editor, works fine, but this method usually works for normal views
I haven't loaded any scripts this time
Thanks I got it now, I changed
#Html.EditorFor(model => model.Details, new {#required="required" })
to
#Html.TextBoxFor(model => model.Details, new {#required="required" })

MetadataType attribute is not working for details view in MVC3

I am newbie in entity framework and I have created Ado.Net Entity Data model which contains two properties FullName and EmailAddress. what I am trying to do is that in my details view I want to display Full Name instead of FullName. To accomplish this I have written code like this:
namespace ScaffFolding.Models
{
[MetadataType(typeof(EmployeeMetaData))]
public partial class Employee
{
}
public class EmployeeMetaData
{
[Display(Name="Full Name")]
public string FullName { get; set; }
[Display(Name = "Email Address")]
public string EmailAddress { get; set; }
}
}
My edmx file also sharing the same namespace and have same class named as Employee
Now the problem is that in Details view this code is not working means showing FullName instead of Full Name but in Create view it's working as expected.
Here is code for my Detail view:
#model ScaffFolding.Models.Employee
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<fieldset>
<legend>Employee</legend>
<div class="display-label">FullName</div>
<div class="display-field">
#Html.DisplayFor(model => model.FullName)
</div>
<div class="display-label">Gender</div>
<div class="display-field">
#Html.DisplayFor(model => model.Gender)
</div>
<div class="display-label">Age</div>
<div class="display-field">
#Html.DisplayFor(model => model.Age)
</div>
<div class="display-label">HireDate</div>
<div class="display-field">
#Html.DisplayFor(model => model.HireDate)
</div>
<div class="display-label">EmailAddress</div>
<div class="display-field">
#Html.DisplayFor(model => model.EmailAddress)
</div>
<div class="display-label">Salary</div>
<div class="display-field">
#Html.DisplayFor(model => model.Salary)
</div>
<div class="display-label">PersonalWebSite</div>
<div class="display-field">
#Html.DisplayFor(model => model.PersonalWebSite)
</div>
</fieldset>
<p>
#Html.ActionLink("Edit", "Edit", new { id=Model.Id }) |
#Html.ActionLink("Back to List", "Index")
</p>
Can anyone please tell me what is going wrong here?
DisplayFor is used for picking up templates from DisplayTemplates folder.
more at What is the #Html.DisplayFor syntax for?
Where as, LabelFor picks stuffs from data annotations
Ok I got the answer what is going wrong here. The problem is in the code generated by VS:
Visual Studio is generating the Details view using div tag as shown below
<div class="display-label">FullName</div>
Where as LabelFor is being used by Vistual Studio for Create view:
#Html.LabelFor(model => model.FullName)

mvc 4 Validation summary appearing before submit

I am creating an application in MVC4.
I have a validationsummary on my page as follows,
<div>
#Html.ValidationSummary()
</div>
when the page loads, it shows the validation summary and says one of the required fields is required. Why is this shown on load? I thought the validation summary was only shown after a submit?
thanks
<div id="GeneratePaymentContainer" class="content-container">
<div>
#Html.ValidationSummary()
</div>
<div id="GeneratePaymentPage1">
<div id="PageHeaderContainer">
<div id="HelpContainer">
<h2>#SearchPayment.SearchPlacementsHeader</h2>
#Html.PageHelp()
</div>
#{ Html.RenderPartial("PlacementFilter", Model); }
</div>
<div id="BodyContainer">
<div id="GridActions" class="buttons-container">
<a id="Print" class="button">#Buttons.PrintButton</a>
</div>
#{ Html.RenderPartial("SearchGridResults", Model); }
<div id="StandardCost"></div>
<div id="SelectedPlacementContainer"></div>
<br />
</div>
</div>
#using (Html.BeginForm("RequestAction", "Request", FormMethod.Post, new { id = "SundryEntryForm" }))
{
}...
try to write your #Html.ValidationSummary() before Html.BeginForm tag
Update : According to this Post
Therefore, just create a css rule as follows;
.validation-summary-valid
{
display:none;
}

MVC3 Embed Models within Models

I am encountering many problems (validation, serialisation) when using models that embed other models and just wanted to know whether anybody has received issue with this kind of thing before. For example I have an enquiry form which has the following model attached:
Model
namespace
{
public class EnquiryStudent
{
public enquiry enquiry { get; set; }
public student student { get; set; }
}
}
The enquiry and student models (embedded inside enquiry student) are auto generated from the database (I am using database first approach).
Now for example a problem I get here is that I use a view to display a form based on the above model:
View
#using (#Html.BeginForm())
{
<div>
<fieldset>
<fieldset>
<legend>Enquiry</legend>
<div class="editor-label">
#Html.LabelFor(m => m.student.firstname)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.student.firstname)
#Html.ValidationMessageFor(m => m.student.firstname)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.student.surname)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.student.surname)
#Html.ValidationMessageFor(m => m.student.surname)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.student.email)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.student.email)
#Html.ValidationMessageFor(m => m.student.email)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.enquiry.subject)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.enquiry.subject)
#Html.ValidationMessageFor(m => m.enquiry.subject)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.enquiry.enquiry_text)
</div>
<div class="editor-field">
#Html.TextAreaFor(m => m.enquiry.enquiry_text)
#Html.ValidationMessageFor(m => m.enquiry.enquiry_text)
</div>
</fieldset>
<p>
<input type="submit" class="rounded-button-gray-shades" value="Send" />
</p>
</fieldset>
</div>
}
and the client side validation works great for everything except the enquiry text (an attribute of the embedded enquiry within EnquiryStudent model, i.e. it doesn't validate this client side only server side??
Now even stranger if I either change the enquiry_text to be a TextBoxFor instead of TextAreaFor it works great.
Or if I make a text area for another entity by adding a dummy field to the EnquiryStudent model (not embedded in another model) it works fine.
Can somebody please shed some light as like I said this is not the only quirk that I have been having with this kind of model relationship.
Thanks,

How to use #model IEnumerable<> and #model <> in the same page (List / Create) MVC3

Lets say i have a class 'Location', and I'm using MVC3 to create a scaffolding list(index.cshtml). The index html page uses #model IEnumerable. If i want to add a new location to the list, i press create, and i end up with a new html page using #model Project.Models.Location.
Instead of going to a new page, i would like to have the create page as a popup using modal in boostrap(twitter). I've tried using partialview without any luck. Whatever i do i get the dictionary error message.
The model item passed into the dictionary is of type 'System.Data.Entity.Infrastructure.DbQuery`1[Project.Models.Location]', but this dictionary requires a model item of type 'Project.Models.Location'.
The modal(bootstrap) itself is working when i'm not fetching the partialview. The partialview itself is exactly the same as the generated create(CRUD).
EDIT: I rewrote the whole thing.
Index:
#model IEnumerable<LoLStats.Models.Location>
#{
ViewBag.Title = "Index";
}
#foreach (var item in Model) {
<ul>
<li>#Html.DisplayFor(modelItem => item.LocationName)</li>
</ul>
}
<a class="btn" data-toggle="modal" href="#myModal" >Create</a>
<div class="modal hide" id="myModal">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h3>Modal header</h3>
</div>
<div class="modal-body">
<p>#Html.Partial("_createLocation")</p>
</div>
<div class="modal-footer">
Close
Save changes
</div>
</div>
_createLocation:
#model LoLStats.Models.Location
#{
ViewBag.Title = "Create"; }
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
Location
<div class="editor-label">
#Html.LabelFor(model => model.LocationName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LocationName)
#Html.ValidationMessageFor(model => model.LocationName)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset> }
You could make a view model that has two properties:
The IEnumerable for the parent view
A singular object for the modal
Then strongly type both views to the view model and you should be all set.
Edit
ViewModel:
public class MyViewModel()
{
public IEnumerable<LoLStats.Models.Location> Locations {get; set;}
public LoLStats.Models.Location Location {get; set;}
}
Index:
#model myNamespace.MyViewModel
...
#foreach (var item in Model.Locations) {
<ul>
<li>#Html.DisplayFor(modelItem => item.Locations.LocationName)</li>
</ul>
...
_createLocation:
#model myNamespace.MyViewModel
...
<div class="editor-label">
#Html.LabelFor(model => model.Location.LocationName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Location.LocationName)
#Html.ValidationMessageFor(model => model.Location.LocationName)
</div>
...
Hopefully that's enough detail to get you going
try this in the Index view:
... <p>#Html.Partial("_createLocation", Model.FirstOrDefault())</p>
on the other hand, maybe this will make more sence:
... <p>#Html.Partial("_createLocation", new LoLStats.Models.Location())</p>
hope it works for you.
Your pop-up would need to have a model defined as Project.Models.Car (singular item). After successfully saving the single item you need to update your original list view. Which you can do using jQuery by inserting a new item into the DOM or just by refreshing the page by navigating to the action that gave you the list to begin with.

Resources