64
votes

Can anyone tell me why client side validation is not working in my MVC 4 application.

_layout.schtml

@Scripts.Render("~/bundles/jquery")
@RenderSection("scripts", required: false)

In my web.config I have:

<appSettings>
   <add key="ClientValidationEnabled" value="true" />
   <add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>

In my login.cshtml page I have:

@using (Html.BeginForm())
{
    <div class="formscontent">

        <ol>
            <li>
                @Html.LabelFor(x => x.AgreementNumber)
                <br />
                @Html.TextBoxFor(x => x.AgreementNumber, new { size = "30" })
                <br />
                @Html.ValidationMessageFor(m => m.AgreementNumber)
                <br />
                <br />
            </li>
            <li>
                @Html.LabelFor(x => x.UserName)
                <br />
                @Html.TextBoxFor(x => x.UserName, new { size = "30" })
                <br />
                @Html.ValidationMessageFor(m => m.UserName)
                <br />
                <br />
            </li>
            <li>
                @Html.LabelFor(x => x.Password)
                <br />
                @Html.PasswordFor(x => x.Password, new { size = "30" })
                <br />
                @Html.ValidationMessageFor(m => m.Password)
                <br />
                <br />
            </li>
        </ol>

    </div>
    
    <ol>
        <li>
            @Html.CheckBoxFor(m => m.RememberMe)
            @Html.LabelFor(m => m.RememberMe, new { @class = "checkbox" })
        </li>
    </ol>
    
    <br />
    
    <input class="mainbutton" type="submit" value="@Model.Localisation.TranslateHtmlString("LogonBtn")" /><br />
    <div style="text-align: left; padding: 0 5px 5px 10px;">
        Forgot login-info? clik <a class="link" href="@Url.Action("Index", "Credentials")">here.</a>
    </div>
    
}

In the bottom of login page:

@section Scripts {
  @Scripts.Render("~/bundles/jqueryval")
}

JavaScript is enabled in my browser. In the MVC 4 template project from Visual Studio client validation works fine.

Running the application, on login page when viewing page source, I see this rendered:

<label for="AgreementNumber">number</label>
<br />
<input id="AgreementNumber" name="AgreementNumber" size="30" type="text" value="387893" />
<br />
<span class="field-validation-valid" data-valmsg-for="AgreementNumber" data-valmsg-  replace="true"></span>

and in this in the bottom:

<script src="/BMWebsite/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/BMWebsite/Scripts/jquery.validate.inline.js"></script>
<script src="/BMWebsite/Scripts/jquery.validate.js"></script>
<script src="/BMWebsite/Scripts/jquery.validate.unobtrusive.js"></script>

My model properties are annotated:

public class LogonModel : ModelBase
{
    [MyRequired("AgreementNumberRequiredProperty")]
    [MyDisplay("AgreementNumberLabel")]
    public string AgreementNumber { get; set; }

    [MyRequired("UserNameRequiredProperty")]
    [MyDisplay("UserNameLabel")]
    public string UserName { get; set; }

    [MyRequired("PasswordRequiredProperty")]
    [DataType(DataType.Password)]
    [MyDisplay("PasswordLabel")]
    public string Password { get; set; }

    [MyDisplay("RememberMeCheckBox")]
    public bool RememberMe { get; set; }
}

MyRequired is a class derived from the regular RequiredAttribute. The reason is that my error messages are localised by overriding the FormatErrorMessage(string name) method of the RequiredAttribute class. And it works fine - My labels and error messages are localized.

MyRequired.cs

public class MyRequiredAttribute : RequiredAttribute
{
    private readonly string _errorMessagekey;

    public MyRequiredAttribute(string errorMessage)
    {
        _errorMessagekey = errorMessage;
    }

    public override string FormatErrorMessage(string name)
    {
        var translation = HttpContext.Current.Session["translation"] as LocalisationHelper;

        return translation != null ? translation.Translate(_errorMessagekey) : ErrorMessage;
    }
}

I put a breakpoint in the POST version of my login action method, and it is being hit. The form is posted to server where server side validation happens. Client side validation doesn't happen.

What am I missing?

Thank you.

21
Can you show us how you are creating the form?Bennor McCarthy
I edited my question and provided more information!Javid
have you overridden the default template by putting something in shared/displaytemplates folder?Dr Blowhard
No I haven't. Just using the standard template.Javid

21 Answers

51
votes

I had the same problem. It seems that the unobtrusive validation scripts were not loaded (see screenshot at the end). I fixed it by adding at the end of _Layout.cshtml

 @Scripts.Render("~/bundles/jqueryval")

The end result:

   @Scripts.Render("~/bundles/jquery")
   @Scripts.Render("~/bundles/jqueryval")
   @RenderSection("scripts", required: false)

Except for my pretty standard CRUD views everything is Visual studio project template defaults.

Loaded scripts after fixing the problem: enter image description here

15
votes

Be sure to add this command at the end of every view where you want the validations to be active.

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}
12
votes

I finally solved this issue by including the necessary scripts directly in my .cshtml file, in this order:

<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>

It's a bit off-topic, but I'm continually amazed by how often this sort of thing happens in Web programming, i.e. everything seems to be in place but some obscure tweak turns out to be necessary to get things going. Flimsy, flimsy, flimsy.

9
votes

you may have already solved this, but I had some luck by changing the order of the jqueryval item in the BundleConfig with App_Start. The client-side validation would not work even on a fresh out-of-the-box MVC 4 internet solution. So I changed the default:

            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                    "~/Scripts/jquery.unobtrusive*",
                    "~/Scripts/jquery.validate*"));

to

        bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                    "~/Scripts/jquery.validate*",
                    "~/Scripts/jquery.unobtrusive*"));

and now my client-side validation is working. You just want to make sure the unobtrusive file is at the end (so it's not intrusive, hah :)

9
votes

In Global.asax.cs, Application_Start() method add:

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(MyRequiredAttribute), typeof(RequiredAttributeAdapter));
7
votes

There are no data-validation attributes on your input. Make sure you have generated it with a server side helper such as Html.TextBoxFor and that it is inside a form:

@using (Html.BeginForm())
{
    ...
    @Html.TextBoxFor(x => x.AgreementNumber)
}

Also I don't know what the jquery.validate.inline.js script is but if it somehow depends on the jquery.validate.js plugin make sure that it is referenced after it.

In all cases look at your javascript console in the browser for potential errors or missing scripts.

7
votes

If you use jquery.validate.js and jquery.validate.unobtrusive.js for validating on client side, you should remember that you have to register any validation attribute of any DOM element on your request. Therefor you can use this code:

$.validator.unobtrusive.parse('your main element on layout');

to register all validation attributes. You can call this method on (for example) : $(document).ajaxSuccess() or $(document).ready() to register all of them and your validation can be occurred successfully instead of registering all js files on cshtml files.

4
votes

I had an issue with validation, the form posts then it validates,

This Doesn't work with jquery cdn

    <script type="text/javascript" src="//code.jquery.com/jquery-1.11.0.js"></script>
    <script src="~/Scripts/jquery.validate.min.js"></script>
    <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

This Works without jquery cdn

<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

Hope helps someone.

4
votes

For me this was a lot of searching. Eventually I decided to use NuGet instead of downloading the files myself. I deleted all involved scripts and scriptbundles and got the following packages (latest versions as of now)

  • jQuery (3.1.1)
  • jQuery Validation (1.15.1)
  • Microsoft jQuery Ubobtrusive Ajax (3.2.3)
  • Microsoft jQuery Unobtrusive Validation (3.2.3)

Then I added these bundles to the BundleConfig file:

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",
                "~/Scripts/jquery.unobtrusive-ajax.js"));

I added this reference to _Layout.cshtml:

@Scripts.Render("~/bundles/jquery")

And I added this reference to whichever view I needed validation:

@Scripts.Render("~/bundles/jqueryval")

Now everything worked.

Don't forget these things (many people forget them):

  • Form tags (@using (Html.BeginForm()))
  • Validation Summary (@Html.ValidationSummary())
  • Validation Message on your input (Example: @Html.ValidationMessageFor(model => model.StartDate))
  • Configuration ()
  • The order of the files added to the bundle (as stated above)
3
votes

The reason that the validation data-* attributes aren't showing in the rendered html for your input could be that there is no form context. The FormContext is created automatically when you create a form using @using(Html.BeginForm(...)) { ... }.

If you use a regular html tag for your form, you won't get client-side validation.

3
votes

My problem was in web.config: UnobtrusiveJavaScriptEnabled was turned off

<appSettings>

<add key="ClientValidationEnabled" value="true" />

<add key="UnobtrusiveJavaScriptEnabled" value="false" />

</appSettings>

I changed to and now works:

`<add key="UnobtrusiveJavaScriptEnabled" value="true" />`
2
votes
<script src="/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>

This code worked for me.

2
votes

In my case the validation itself was working (I could validate an element and retrieve a correct boolean value), but there was no visual output.

My fault was that I forgot this line @Html.ValidationMessageFor(m => ...)

The TS has this in his code and got me on the right track, but I put it in here as reference for others.

2
votes

this works for me goto your model class and set error message above any prop

[Required(ErrorMessage ="This is Required Field")]
    public string name { get; set; }

import namespace for Required by Ctrl+. and finally add this in view

<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
1
votes

the line below shows you haven't set an DataAttribute like required on AgreementNumber

<input id="AgreementNumber" name="AgreementNumber" size="30" type="text" value="387893" />

you need

[Required]
public String AgreementNumber{get;set;}
0
votes

Use:

@Html.EditorFor

Instead of:

@Html.TextBoxFor

0
votes

I created this html <form action="/StudentInfo/Edit/2" method="post" novalidate="novalidate"> where the novalidate="novalidate" was preventing the client-side jQuery from executing, when I removed novalidate="novalidate", client-side jQuery was enabled and stared working.

0
votes

I'll like to add to this post, that I was experienceing the same issue but in a PartialView.

And I needed to add

<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

To the partial view, even if already present in the _Layout view.

References:

0
votes

Im my case I added and id equals to the name automatically generated for VS on the html and in the code I´ve added a line to that case.

$(function () {
            $.validator.addMethod('latinos', function (value, element) {
                return this.optional(element) || /^[a-záéóóúàèìòùäëïöüñ\s]+$/i.test(value);
            });

            $("#btn").on("click", function () {
                //alert("aa");
                $("#formulario").validate({                    
                    rules:
                    {
                        email: { required: true, email: true, minlength: 8, maxlength: 80 },
                        digitos: { required: true, digits: true, minlength: 2, maxlength: 100 },
                        nombres: { required: true, latinos: true, minlength: 3, maxlength: 50 },
                        NombresUsuario: { required: true, latinos: true, minlength: 3, maxlength: 50 }
                    },
                    messages:
                    {
                        email: {
                            required: 'El campo es requerido', email: 'El formato de email es incorrecto',
                            minlength: 'El mínimo permitido es 8 caracteres', maxlength: 'El máximo permitido son 80 caracteres'
                        },
                        digitos: {
                            required: 'El campo es requerido', digits: 'Sólo se aceptan dígitos',
                            minlength: 'El mínimo permitido es 2 caracteres', maxlength: 'El máximo permitido son 10 caracteres'
                        },
                        nombres: {
                            required: 'El campo es requerido', latinos: 'Sólo se aceptan letras',
                            minlength: 'El mínimo permitido es 3 caracteres', maxlength: 'El máximo permitido son 50 caracteres'
                        },
                        NombresUsuario: {
                            required: 'El campo es requerido', latinos: 'Sólo se aceptan letras',
                            minlength: 'El mínimo permitido es 3 caracteres', maxlength: 'El máximo permitido son 50 caracteres'
                        }
                    }
                });
            });

<tr>@*<div class="form-group">     htmlAttributes: new { @class = "control-label col-md-2" }      , @class = "form-control" }*@
                <td>@Html.LabelFor(model => model.NombresUsuario )</td>

                        @*<div class="col-md-10">*@
                <td>
                    @Html.EditorFor(model => model.NombresUsuario, new { htmlAttributes = new { id = "NombresUsuario" } })
                    @Html.ValidationMessageFor(model => model.NombresUsuario, "", new { @class = "text-danger" })
                </td>
0
votes

Ensure that you are using Attributes (e.g. RequiredAttribute) which comes under System.ComponentModel.DataAnnotations namespace

-2
votes
  @section Scripts
 {
<script src="../Scripts/jquery.validate-vsdoc.js"></script>
<script src="../Scripts/jquery.validate.js"></script>
<script src="../Scripts/jquery.validate.min.js"></script>
<script src="../Scripts/jquery.validate.unobtrusive.js"></script>
<script src="../Scripts/jquery.validate.unobtrusive.min.js"></script>
}