问题
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.
来源:https://stackoverflow.com/questions/44435766/mvc-asp-net-client-side-validation-not-working