Best approach for extending unobtrusive javascript in MVC3 to add a style to a div client side
Asked Answered
D

7

30

I'm using html5/Razor/MVC3 leveraging the Bootstrap template from Twitter. I want to have form validation that looks slick like they've documented (http://twitter.github.com/bootstrap/#forms). So if we take a look at how the standard boiler-plate MVC3 for account registration, the markup would look like:

@using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class="form-stacked" })) {
    @Html.ValidationSummary(true, "Snap! Something went wrong")
    <div>
        <fieldset>
            <legend>Account Information</legend>
            <div class="clearfix error">
                @Html.LabelFor(m => m.UserName)
                <div class="input">
                    @Html.TextBoxFor(m => m.UserName)
                    <span class="help-inline">@Html.ValidationMessageFor(m => m.UserName)</span>
                </div>
            </div>

            <div class="clearfix">
                @Html.LabelFor(m => m.Email)
                <div class="input">
                    @Html.TextBoxFor(m => m.Email)
                    <span class="help-inline">@Html.ValidationMessageFor(m => m.Email)</span>
                </div>
            </div>

            <div class="clearfix">
                @Html.LabelFor(m => m.Password)
                <div class="input">
                    @Html.PasswordFor(m => m.Password)
                    <span class="help-inline">@Html.ValidationMessageFor(m => m.Password)</span>
                </div>
            </div>

            <div class="clearfix">
                @Html.LabelFor(m => m.ConfirmPassword)
                <div class="input">
                    @Html.PasswordFor(m => m.ConfirmPassword)
                    <span class="help-inline">@Html.ValidationMessageFor(m => m.ConfirmPassword)</span>
                </div>
            </div>
        </fieldset>
        <div class="actions">
            <button class="btn large primary" type="submit">Register</button>
        </div>
    </div>

What I want to do is have the container div inject the "error" class like I've hard-coded in the first input. (So upon entering the page, the div would have a class of "clearfix" but if that input block failed validation, it would tag it as "clearfix error"). I figure I'm going to have to update the div block to include an id of some sort and perhaps add a new data- attribute to the ValidationMessage. I don't have a problem extending the ValidationMessageFor helper. I'm just not 100% sure what the approach should be for extending the library that's there. Any suggestions on how to approach this?

TIA.

UPDATE:

I am thinking this approach is reasonable:

<div id="UserNameContainer" class="clearfix error">
    @Html.LabelFor(m => m.UserName)
    <div class="input">
        @Html.TextBoxFor(m => m.UserName)
        <span class="help-inline">@Html.ValidationMessageFor(m => m.UserName, null, new { @data_container = "UserNameContainer" })</span>
    </div>
</div>

By decorating my validation message with a data-container name, I could then target the container div. Now I just need to figure out how to intercept the validation message.

Dekeles answered 27/8, 2011 at 15:27 Comment(2)
Have you managed to solve this?Serra
So @JBright, did you solve this or did one of these answer the question?Autolycus
K
52

The $.validator.setDefaults method solved this issue for me with Bootstrap from Twitter. I'm usingjquery.validate.js and jquery.validate.unobtrusive.js.

Since unobtrusive validation on DOM ready scans your document and caches unobtrusive validation options for each form it encounters, it is needed to call the $.validator.setDefaults method before document scan occurs.

// setup defaults for $.validator outside domReady handler
$.validator.setDefaults({
    highlight: function (element) {
        $(element).closest(".clearfix").addClass("error");
    },
    unhighlight: function (element) {
        $(element).closest(".clearfix").removeClass("error");
    }
});

$(document).ready(function() {
       // do other stuff
});
Knitwear answered 10/10, 2011 at 16:59 Comment(1)
If you also like server errors highlighted use something like $('form .input-validation-error').closest(".clearfix").addClass("error"); on document ready.Algonkian
O
4

Came accross the same issue. I am tackling it by adding and extesion to the HtmlHelper Class.

This is what I did for the ValidationSummary:

   public static class TwitterBootstrapHelperExtensions
    {
        public static MvcHtmlString BootstrapValidationSummary(this HtmlHelper helper,
                               bool excludePropertyErrors,
                               string message)
        {
            if(helper.ViewData.ModelState.Values.All(v => v.Errors.Count == 0)) return new MvcHtmlString(string.Empty);

            string errorsList = "<ul>";
            foreach (var error in helper.ViewData.ModelState.Values.Where(v => v.Errors.Count >0))
            {
                errorsList += string.Format("<li>{0}</li>", error.Errors.First().ErrorMessage);
            }
            errorsList += "</ul>";
            return new MvcHtmlString(string.Format("<div class=\"alert-message error\"><span>{0}</span>{1}</div>",message,errorsList));

        }
    }

And in the .cshtml file I replace Html.ValidationSummary with this:

@Html.BootstrapValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.")

Remember to add the namespance of your extension class in the views folder web.config file.

I will post here later if I tackle the individual input item before you. HTH

Outdated answered 1/9, 2011 at 18:26 Comment(1)
I did something similar--a "BootstrapValidationSummary" that could optionally be used. My code is pretty close to my original update, but I like what Germán proposed with jquery.Dekeles
M
1

Rather than reinventing this particular wheel, check the validationEngine plugin available at http://www.position-absolute.com/articles/jquery-form-validator-because-form-validation-is-a-mess/.

You can customize the popup elements as you want, and it is trivial to connect to jQuery.validate.js.

Mockingbird answered 28/8, 2011 at 4:14 Comment(0)
M
1

I prefere to change the CSS of bootstrap. Just added the classes of jQuery validate in the right place. field-validation-error and input-validation-error

    form .clearfix.error > label, form .clearfix.error .help-block, form .clearfix.error .help-inline, .field-validation-error {
  color: #b94a48;
}
form .clearfix.error input, form .clearfix.error textarea, .input-validation-error {
  color: #b94a48;
  border-color: #ee5f5b;
}
form .clearfix.error input:focus, form .clearfix.error textarea:focus, .input-validation-error:focus {
  border-color: #e9322d;
  -webkit-box-shadow: 0 0 6px #f8b9b7;
  -moz-box-shadow: 0 0 6px #f8b9b7;
  box-shadow: 0 0 6px #f8b9b7;
}
Minsk answered 4/1, 2012 at 12:38 Comment(0)
N
1

You can integrate MVC3 validation with Bootstrap framework by adding the following javascript to your page (View)

<script>
$(document).ready(function () {
/* Bootstrap Fix */
$.validator.setDefaults({
    highlight: function (element) {
        $(element).closest("div.control-group").addClass("error");
    },
    unhighlight: function (element) {
        $(element).closest("div.control-group").removeClass("error");
    }
});
var current_div;
$(".editor-label, .editor-field").each(function () {
    var $this = $(this);
    if ($this.hasClass("editor-label")) {
        current_div = $('<div class="control-group"></div>').insertBefore(this);
    }
    current_div.append(this);
});
$(".editor-label").each(function () {
    $(this).contents().unwrap();
});
$(".editor-field").each(function () {
    $(this).addClass("controls");
    $(this).removeClass("editor-field");
});
$("label").each(function () {
    $(this).addClass("control-label");
});
$("span.field-validation-valid, span.field-validation-error").each(function () {
    $(this).addClass("help-inline");
});
$("form").each(function () {
    $(this).addClass("form-horizontal");
    $(this).find("div.control-group").each(function () {
        if ($(this).find("span.field-validation-error").length > 0) {
            $(this).addClass("error");
        }
    });
});
});
</script>

Besides, on the Views (for example "Create.cshtml") make sure that the fields in the form are formatted as the following...

    <div class="editor-label">
        @Html.LabelFor(Function(model) model.Name)
    </div>
    <div class="editor-field">
        @Html.EditorFor(Function(model) model.Name)
        @Html.ValidationMessageFor(Function(model) model.Name)
    </div>

With this solution, it will most likely be enough to just add a javascript without edit the View.

Notary answered 14/12, 2012 at 14:47 Comment(0)
N
0

What I've done is taken the css classes for the validation errors and created a new css file with the same classes but with bootstrap values.

You can find it in a nuget package at: http://nuget.org/List/Packages/MahApps.Twitter.Bootstrap

That also provides some scaffolding templates to autocreate new views.

Nev answered 17/11, 2011 at 5:29 Comment(0)
A
0

I needed to solve this using Bootstrap 3.1 and Razor. This is what I used:

$.validator.setDefaults({
    highlight: function (element) {
        $(element).parents(".form-group").addClass("has-error");
    },
    unhighlight: function (element) {
        $(element).parents(".form-group").removeClass("has-error");
    }
});

$(function () {

    $('span.field-validation-valid, span.field-validation-error').each(function () {
        $(this).addClass('help-block');
    });

    $('form').submit(function () {
        if ($(this).valid()) {
            $(this).find('div.form-group').each(function () {
                if ($(this).find('span.field-validation-error').length == 0) {
                    $(this).removeClass('has-error');
                }
            });
        }
        else {
            $(this).find('div.form-group').each(function () {
                if ($(this).find('span.field-validation-error').length > 0) {
                    $(this).addClass('has-error');
                }
            });
        }
    });

    $('form').each(function () {
        $(this).find('div.form-group').each(function () {
            if ($(this).find('span.field-validation-error').length > 0) {
                $(this).addClass('has-error');
            }
        });
    });
});

This is a combination of @german's answer and help from this post by "theBraindonor". Updated to use new Bootstrap 3 classes.

Autolycus answered 7/11, 2013 at 17:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.