views:

3207

answers:

4

I am trying to tap into the HTML.ValidationMessage() element to write so really custom client side validation with jQuery. Is this even possible? My server side validation is displayed using the HTML.ValidationMessage(), and I am wondering how I would access that element to display a custom message using jQuery before a form submit.

I know there are a few plugins out there to do some of this stuff, but I would really like complete control with my validation.

Here is a bit of the Javascript code I have currently. Basically it adds the validation "class" to the input element on submit, however not sure how to access the Html.ValidationMessage to output something like "Email required."

    <script type="text/javascript">
    $(document).ready(function() {
        $("input[type=submit]").click(function() {

            var valid = true;

            // email blank
            if ($("input[name='email']").val().length < 1) {
                $("input[name='email']").addClass("input-validation-error");
                valid = false;
            }

            return valid;
        })
    });

</script>

And Code from the View:

       <p>
            <label for="email">
                Email:</label>
            <%= Html.TextBox("email") %>
            <%= Html.ValidationMessage("email") %>
        </p>
+1  A: 

If you put the message statically in the page and set it's display to "none", you could show that message at the same time you change the class for the input field.

    <p>
        <label for="email">
            Email:</label>
        <%= Html.TextBox("email") %><span style="display:none" class="email-error">Email required</span>
        <%= Html.ValidationMessage("email") %>
    </p>

Then in your JS add this line under the part change this:

        if ($("input[name='email']").val().length < 1) {
            $("input[name='email']").addClass("input-validation-error");
            valid = false;
        }

to this:

        if ($("input[name='email']").val().length < 1) {
            $("input[name='email']").addClass("input-validation-error");
            $("span.email-error").show();
            valid = false;
        }

You may need some CSS to position that stuff accordingly, but functionally it should do what you want.

EDIT:

To avoid extra markup replace:

$("span.email-error").show();

with:

$("input[name='email']").after('<span style="display:none" class="email-error">Email required</span>');
dhulk
Thanks for your answer. Only problem here is the additional mark-up required to pull this off.
aherrick
You could actually insert that span tag in the jQuery if you don't want to add the extra markup.
dhulk
A: 

Create an HtmlHelper that is a ValidatedTextBox. I've done this using reflection on my models, creating a fully dynamic jQuery integration with validation, but a simpler version would work like this (this will probably work but is untested as it stands). A good place to start:

public static MvcForm BeginClientValidatedForm(this HtmlHelper helper, string formId)
{
    HttpResponseBase response = helper.ViewContext.HttpContext.Response;
    if (helper.ViewData.ModelState.IsValid)
    {
        response.Write("<ul class=\"validation-summary-errors\"></ul>\n\n");
    }

    response.Write(ClientValidationHelper.GetFormValidationScript(formId));
    response.Write("\n");

    // Inject the standard form into the httpResponse.
    var builder = new TagBuilder("form");
    builder.Attributes["id"] = formId;
    builder.Attributes["name"] = formId;
    builder.Attributes["action"] = helper.ViewContext.HttpContext.Request.Url.ToString();
    builder.Attributes["method"] = HtmlHelper.GetFormMethodString(FormMethod.Post);
    response.Write(builder.ToString(TagRenderMode.StartTag));

    return new MvcForm(response);
}

And the corresponding "GetFormValidationScript":

public static string GetFormValidationScript(string formId)
  {
    string scriptBlock =
    @"<script type=""text/javascript"">
    $(document).ready(function() {{
      $(""#{0}"").validate({{
        meta:""rules"",
        onkeyup:false,
        onfocusout:false,
        onclick:false,
        errorClass:""input-validation-error"",
        errorElement:""li"",
        errorLabelContainer:""ul.validation-summary-errors"",
        showErrors: function(errorMap, errorList) {{
            $(""ul.validation-summary-errors"").html("""");
            this.defaultShowErrors();
      }}";

      // etc...this is the standard jQuery.validate code.

      return string.Format(scriptBlock, formId);


  }

public static string ClientValidatedTextbox(this HtmlHelper htmlHelper, string propertyName, IDictionary<string, object> htmlAttributes, string validationType)
{
    var cssClassBuilder = new StringBuilder();
    cssClassBuilder.Append("text ");
    if (htmlAttributes == null)
    {
        htmlAttributes = new Dictionary<string, object>();
    }
    else if(htmlAttributes.ContainsKey("class"))
    {
        cssClassBuilder.Append(htmlAttributes["class"]);
    }

    switch validationType
    {
      case "email":
        cssClassBuilder.Append(" {rules: {email: true, messages: {email: 'A valid email is required.'}} } ");
        break;
    }

    htmlAttributes["class"] = cssClassBuilder.ToString();

    return htmlHelper.TextBox(propertyName, htmlAttributes);
}
Peter J
+8  A: 

You could write a ton of code to do this. Or you could just use xVal, which is free and does exactly this, plus much more. Put value annotations on your .NET types, add a couple of simple things to your aspx, and you get jQuery validation for free. Plus it comes with providers for popular frameworks, and it's very customizable in case you need more complex validation.

I see no need to reinvent the wheel here.

Craig Stuntz
A: 

Would it be an idea to just use the jquery form validation plugin for client side ? It's easy to implement in the view code. You add a few tags to the input boxes and add a few lines of javascript in the header and you're done. Ofcourse you'd still have to code anything that's 'very custom' so to speak.

Morph