Search code examples
jqueryajaxasp.net-mvcunobtrusive-validation

Use Remote validation in ASP.NET MVC without form on View


I use Remote attribute on my ViewModel in ASP.NET MVC 4 application. Here is my simple model:

public class User
{
    [Required(AllowEmptyStrings = false, ErrorMessage = "test test")]
    public int Id { get; set; }

    [DisplayName("Email")]
    [Remote("RemoteValidateEmailLengthValidation", "Home")]

    public string Email { get; set; }
}

And remote validation method:

public JsonResult RemoteValidateEmailLengthValidation(string Email)
{
    if (Email.Length > 20)
    {
        return Json("Too long email", JsonRequestBehavior.AllowGet);
    }
    else
    {
        return Json(true, JsonRequestBehavior.AllowGet);
    }
}

I added all scripts that i need for validation on Layout:

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

Write all that i need for validation in WebConfig:

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

And add simple Controller that creates empty model and return View.

@model ViewModels.User

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

@using (Html.BeginForm("PostUser", "Home", FormMethod.Post))
{
    @Html.EditorForModel()
    <input type="submit" />
}

It works only if i wrap my model in form and doesn't work if i write my View like this:

@model ViewModels.User

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

@Html.EditorForModel()

So i have questions:

  1. Why remote validation doesn't work without form? Because in Chrome debugger i see that form don't submit i see only Validation method call.
  2. Which javascript method used by Remote validation? OnChange? Can i see it anywhere and can i change it?

Solution

  • Client side unobtrusive validation involves

    1. On the server side: All HtmlHelper used for generating form controls internally call the GetUnobtrusiveValidationAttributes method of HtmlHelper. Various checks are performed and if not all conditions are met (such as UnobtrusiveValidation has been disabled) then the data-val attributes necesary for client side validation are not rendered
    2. On the client side: When jquery.validation.unobtrusive.js is loaded, it first checks for the existence of a <form> tag, then based on the data-val attributes, add the rules,messages etc. for use by jquery.validate.

    The first function called is

    parse: function (selector) {
        var $forms = $(selector)
            .parents("form")
            .andSelf()
            .add($(selector).find("form"))
            .filter("form");
        ....
    

    where selector is the html document element. If there is no <form> element, var $forms is undefined and nothing more is executed. Client side validation simply does not work if there is no <form> element.

    Its unclear why you would generate html form controls that are not in a form, but you could simply make your own call to the controller function, return a message and display it

    public JsonResult RemoteValidateEmailLengthValidation(string Email)
    {
        if (Email.Length > 20)
        {
            return Json("Too long email", JsonRequestBehavior.AllowGet);
        }
        else
        {
            return Json(null, JsonRequestBehavior.AllowGet);
        }
    }
    

    and the script

    var url = '@Url.Action("RemoteValidateEmailLengthValidation", "Home")';
    var placeHolder = $('[data-valmsg-for="Email"]');
    $('#Email').change(function() {
      $.getJSON(url, { Email: $(this.val() }, function(response) {
        if(response) {
          placeHolder.text(response).removeClass('field-validation-valid').addClass('field-validation-error');
        }
      });
    });
    

    and also handle the .keyup event to remove error message and reset the class name