MVC5 Validation Errors in Razor View - asp.net-mvc

I am using MVC5 and having problem displaying the validation errors of an object both in the Validation Summary section and the individual validation messages for each control.
Lets put aside client validation for the moment although we have ENABLED IT in the web config and included the js files.
If a model that is invalid is passed to a view that has in place a Validation Summary (setting excludePropertyErrors to false) and for each control there is a #Html.ValidationMessageFor(model => model.Summary, "", new { #class = "text-danger" }), shoudn't all these display the Validation errors in the object when the page loads.
We checked the object and the framwork knows it is invlaid (ModelState.IsValid is definitely false) and the errors collection contains several validation errors
(System.Data.Entity.Validation.DbValidationError) but none of them show up neither in the ValidationSummary or the ValidationMessage for the individual controls when the page loads.
Currently I am getting he validation errors manually by context.Entry(prop).GetValidationResult().ValidationErrors.ToList(); and passing it to the Viewbag and iterate over them in the view to display them. Seems crazy!
P.S. The main View is composed of several partial views in which the controls are and the Vaidationsummary is in the Main containing view.
public async Task<ActionResult> GetProduct(id)
{
var product= await context.Products.FindAsync(id);
return View(product);
}
As I mentioned , there are NO VALIDATION MESSAGES ANYWHERE. If we turn off client side validation the input control html is
<input class="form-control text-box single-line valid" id="Price" name="Price" style="font-weight:bold" type="text" value="" aria-invalid="false">
As you can see the value is empty BUT it says it is valid even though the field is a required field marked so via DataAnnotations and the Model is INVALID and includes validation error that Price field is required!
Here is the code:
<div class="form-group">
#Html.LabelFor(m => m.Price, new { #class = "col-sm-3 control-label" })
<div class="col-sm-5">
#Html.EditorFor(model => model.Price, new { htmlAttributes = new { #class = "form-control", style = "font-weight:bold" } })
#Html.ValidationMessageFor(model => model.Price, "", new { #class = "text-danger" })
</div>
</div>
And this is the generated html with client side validation enabled :
<input class="form-control text-box single-line" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" style="font-weight:bold" type="text" value="">
Would greatly appreciate any assistance.

Related

MVC/ASP.NET: Client side validation not working

EDIT: Consider this whole question replaced by this one:
ASP.NET/MVC: Knockout-binding preventing client-side validation from being performed?
Working in ASP.NET/MVC, I’m having great trouble getting the (unobtrusive or even non-unobtrusive) client side validation to work. (Yes again, but this time for different reasons as it appears.)
NB: The EDITS towards the bottom of the post are important, esp. EDITS 2 and 3.
Problem is, client side validation does absolutely nothing (see below), even though all ingredients seem to be in place. I’ve read through quite a few questions and answers here on Stack Overflow, and it seems everything is done correctly in my project, but still it doesn’t work. What am I missing?
In my Web.config file (the one in the root folder, not the one in the View folder), I’ve explicitly enabled the client side validation:
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
And all the relevant Javascript files are there, in the right order and loading correctly (and I’ve made no changes to them obviously). I’ve included them in bundles, in BundleConfig:
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate.js", "~/Scripts/jquery.validate.unobtrusive.js"));
I add these bundles in my View (well actually in the shared _Layout.cshtml parent view):
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/bootstrap")
#Scripts.Render("~/bundles/knockout")
And in the generated source code for the View these scripts (and a few others) appear as follows:
Which, as far as I can tell, is correct. (I also use the jQuery as well as knockout extensively in other places in the same View.) Also, no loading errors in the browser console.
Then in my ViewModel, I have this annotated property Email (among others):
public class RegisterViewModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
// some other properties…
}
And this is the corresponding code in my View:
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
Which generates the following source code (click to enlarge):
Which also seems correct, as far as I can tell.
But then when I type something that’s evidently not a valid email-address in the input field, and make the field lose focus (by jumping to the next field), NO ERROR MESSAGE appears. Neither in the summary, nor the specific error message for the email field itself. As seen here:
(The little red square is the .field-validation-valid element that should contain the error message, but doesn't. For testing purposes I had decorated this element with a red border.)
Also, when I press the submit button, the input fields are simply submitted to the server action method (which then correctly determines that the inputs are not valid). But in fact, with client side validation enabled, the submit shouldn’t happen unless client side validation succeeds. But well, that’s basically the whole issue: client side validation simply doesn’t happen, despite the correct HTML being generated (presumably!).
EDIT 1:
And here is the HTML/Razor for the whole form:
#model Treinen2.Models.RegisterViewModel
#{
ViewBag.Title = "Register";
}
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
This is in a shared View called Register.cshtml, which -- depending on certain conditions -- gets displayed by calling #Html.Partial("Register") from the home view Index.cshtml. [I'm kind of trying to build a single page API application, as an exercise, so everything is included in the homepage (Index), and all navigation happens client side (with the obvious exception of the submit of the "Register" button itself, which gets sent to the server Action method, at least for now). And with obviously only one part ('page') of Index.cshtml being displayed at any one time, for which I use knockout binding.]
EDIT 2:
OK, I've noticed the following: If I put the same form in Index.cshtml, and also add the same model to that Index view, then client-side validation works perfectly. It's only on the partial view that it fails to work. Which suggests that I could simply stop using the partial view, and instead simply include its content on Index.cshtml, as tested. On the other hand, I still don't understand WHY using the partial view for the register form wouldn't work too. (With this new information, I may have to ask the question anew in a different form, but don't have the time right now...) [/EDIT 2]
EDIT 3:
Seems I'm edging closer to understanding the root cause of the problem. Because now I have the validation working with the form on the Index view... BUT it stops working as soon as I put the whole form inside a DIV-element that is bound by a Knockout attribute data-bind="If: ....." So that seems to be the essence of the problem: the interaction between client-side validation and Knockout binding. The Knockout binding, which in and of itself works fine, seems to prevent the validation from being performed. Although I still don't understand why that should be the case. [/EDIT 3]
So, what am I missing? Any constructive suggestions appreciated, will check back in a few hours.

Html.ValidationMessageFor not displaying at all

I have the following form:
<form action="~/buy-online" method="get" class="buy-online-form clearfix" autocomplete="off" id="buy-online-search">
<div class="infield-holder clearfix">
#Html.LabelFor(m => m.CustomerPostcode, new { #class = "infield" })
#Html.TextBoxFor(m => m.CustomerPostcode, new { #class = "textbox" })
<input type="submit" value="Buy Online" id="find-retailer-button" class="button" />
</div>
</form>
#Html.ValidationMessageFor(m => m.CustomerPostcode)
Which works fine and will display an error message when submitted without jQuery, but when I add the jQuery validate scripts (v 1.11.1):
<script src="/scripts/jquery.validate.js"></script>
<script src="/scripts/jquery.validate.unobtrusive.js"></script>
It stops the form submitting but doesn't display the error message
My property is marked like so:
[DisplayName("Enter your full postcode")]
[Required(ErrorMessage = "Please enter your full postcode")]
public string CustomerPostcode { get; set; }
And the html renders like this:
<input class="textbox" data-val="true" data-val-required="Please enter your full postcode" id="CustomerPostcode" name="CustomerPostcode" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="CustomerPostcode" data-valmsg-replace="true"></span>
If I inspect the input when I hit submit it is adding the class input-validation-error to the textbox but just not updating the validation message.
All the posts that I have checked on this problem just say to include the scripts so I'm at a loss as to why the message is not showing.
I've even tried adding the jquery.unobtrusive-ajax.js script but that didn't seem to do anything either. Any help would be appreciated, thanks.
You need to include the #Html.ValidationMessageFor(m => m.CustomerPostcode) within the form tags for jquery.validate.unobtrusive to work.

Client Side MVC Validation not firing on mouse(Tab) out

Am trying to have client side validation using Data Annotations and JQUERY for my web page.
I have set up my property in model
[Required]
public string Name { get; set; }
And i set up Scripts using Bundle.config which is rendered in my page as below
<script src="/Scripts/jquery-1.10.2.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
and in my web.config
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
My HTML is renderd as expected
<input type="text" value="" name="Name" id="Name" data-val-required="The Name field is required." data-val="true" class="text-box single-line">
On click of Submit the Client side validation is firing as Expected.
My problem is Why it is not firing on mouse or Tab out ??
Am i missing something or doing wrong ?? I searched and tried everything but still validation not works on mouse or Tab out.
Even i tried creating a new sample with just one property but still i cant make it work. Any Help would be appreciated
Thanks
---Updated with view code sample ---
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
....
sample code may be brackets missing

Add a non field related error to an asp mvc form

I'm having some troubles with ASP MVC error handling.
On a form that a user tries to connect to a device. If the uses input an invalid device name, it's pretty straightforward to tell the user the name is invalid.
I'm implementing IEnumerable<RuleViolation> GetRulesViolations() on all my data classes. The RuleViolation class has two fields: PropertyName and ErrorMessage and if I get an error on submit I just call the GetRulesViolations method and set the errors on the ModelState:
catch {
foreach (var issue in device.GetRulesViolations()) {
ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
}
return View();
}
and with some background asp mvc magic the error appears on the view in the ValidationMessage placeholder for the model.Name:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<p>
<input type="submit" value="Connect" />
</p>
</fieldset>
}
Now the problem:
If the error i'm getting is something like "Could not connect to the device" that's not a problem related to the Name field. It's a message that should appear above the form because it's related to the whole form.
Is there a straightforward way to set this like ModelState.AddError("error message") without telling the key so it would apply to the whole form or should I create an Error hidden property on the Data classes and place a validation message for that property above the form?
Yes, empty field name, like this :
ModelState.AddModelError("", issue.ErrorMessage);

input-validation-error on other input element?

I have a model which has 2 fields, "a" and "b" like this:
class AbModel
{
public string a {get;set;}
[SomeValidation]
public int b {get;set;}
}
Now "b" is actually hidden in the gui, and "a" shows a textual representation of it.
<div class="editor-field">
<%= Html.HiddenFor(model => model.b, new { id = "ABModelEditor_b" })%>
<%= Html.TextBoxFor(model => model.a, new { id = "ABModelEditor_a" })%>
<input type="button" value="Change" onclick="AbModelEditorScript.showAbSelector(); return false;" />
</div>
Generates the following on "save" with empty data:
<div class="editor-field">
<input class="input-validation-error" id="ABModelEditor_b" name="b" type="hidden" value="">
<input id="ABModelEditor_a" name="a" type="text" value="">
<input type="button" value="Change" onclick="AbModelEditorScript.showAbSelector(); return false;" />
</div>
I need the the input-validation-error css class to be attached to the "a" textbox instead of the hidden for "b".
Before I simply move the css-class with a jquery-script, is there some other way that I should consider, perhaps some built in functionality?
Are you using unobtrusive validation? The other option is to add the validation attributes with jQuery and revalidate the form...
$("#ABModelEditor_a").attr("data-val-required", "true"); //add your validation attributes to the input tag
var form = $("form");
form.removeData("validator").removeData("unobtrusiveValidation") // this will clear the validation from the form
$.validator.unobtrusive.parse(form); //reattach the validation
This will give you real client side validation, but it still won't match your model. You'll have to fill in the gap on the server side.
In regards to your comment about server-side only validation.
You can try to manually add the model error to the model state. This should be reflected in your view when you return.
ModelState.AddModelError(string key, string errorMessage);

Resources