Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fire jquery unobtrusive validation with bootstrap , Asp.net Mvc 3 and backbone

I tried to find the bits of information available on the net, But couldn't hook it up together. I have an application which makes use of a login page. Now I'm not binding the view to any model. However I have two inputs (Username and password). I want to fire the jquery unobtrusive validation feature that comes with Asp.net Mvc. Here are the samples:

Backbone Template with Twitter bootstrap which is the Login template (underscore templating engine).

@using (@Html.BeginForm("Login", "Home", FormMethod.Post, new { @class = "form-horizontal" }))
               {
               <div class="modal-body">
                   <div class="control-group">
                        <label class="control-label" for="inputEmail">Email</label>
                        <div class="controls">
                            @*<input type="text" id="inputEmail" placeholder="Email">*@
                            @Html.TextBox("Email", "", new { @placeholder = "Email" })
                        </div>
                    </div>
                    <div class="control-group">
                        <label class="control-label" for="inputPassword">Password</label>
                        <div class="controls">
                            <input type="password" id="inputPassword" placeholder="Password">
                        </div>
                    </div>
                    <div class="control-group">
                    @*<div class="controls">
                        <label class="checkbox">
                            <input type="checkbox"> Remember me
                        </label>
                        <button type="submit" class="btn">Sign in</button>
                    </div>*@
                </div>
             </div>
               <div class="modal-footer">
                    @*<a class="btn" href="#" id="closeBtn">Close</a>*@ <button type="submit" class="btn btn-primary" >Login</button>
               </div>
               }  

The Coffeescript for Login view

require ['backbone','bootstrap','jqValUnobtrusive'],(Backbone) ->   
class LoginView extends Backbone.View

    el:$("#content")        

    initialize: ->                      
        @render()
        @validationOptions = @options.validationOptions

    validationOptions:
        rules:
            'Email':
                required:true
            'user[password]':
                required:true
    close:->
        console.log "hello"
    render : ->     
        $(@el).find("#login").html _.template $("#loginTemplate").html() 

App = new LoginView

And My controller to add Server side logic to validation rule in absence of javascript from the browser

[HttpPost]
    [ValidateInput(true)]
    public ActionResult Login(FormCollection Form)
    {
        ViewBag.Message = "Method posted";
        if (Form["Email"] == string.Empty)
        {
            ModelState.AddModelError("Email", "Please Provide a Username");
            ModelState.SetModelValue("Email", ValueProvider.GetValue("Email"));

        }
        return View();
    }

Would someone be able to shine some light on this problem? How to put the twitter bootstrap validation messages with this jquery unobtrusive code to show the errors? Or extend the jquery unobtrusive validation plugin to work with twitter bootstrap / backbone to perform the validation?

My criteria is the username and password shouldn't be NULL or blank . A simple case for study for validating a form without model binding (I dont want to bind the Login page to any model). Rather hook up the jquery unobtrusive plugin with extending backbone and twitter bootstrap styling!

like image 744
Joy Avatar asked Oct 11 '12 07:10

Joy


3 Answers

Here is my method for replacing jquery error messages with bootstrap styles when using mvc unobtrusive validation:

 /*
 * Form Validation
 * This script will set Bootstrap error classes when form.submit is called.
 * The errors are produced by the MVC unobtrusive validation.
 */
 $(function () {
     $('form').submit(function () {
         $(this).find('div.control-group').each(function () {
             if ($(this).find('span.field-validation-error').length == 0) {
                 $(this).removeClass('error');
             }
         });

         if (!$(this).valid()) {
             $(this).find('div.control-group').each(function () {
                 if ($(this).find('span.field-validation-error').length > 0) {
                     $(this).addClass('error');
                 }
             });
         }
     });
     $('form').each(function () {
         $(this).find('div.control-group').each(function () {
             if ($(this).find('span.field-validation-error').length > 0) {
                 $(this).addClass('error');
             }
         });
     });
 });
 var page = function () {
     //Update that validator
     $.validator.setDefaults({
         highlight: function (element) {
             $(element).closest(".control-group").addClass("error");
         },
         unhighlight: function (element) {
             $(element).closest(".control-group").removeClass("error");
         }
     });
 } ();
 /* End Form Validation */

There is some talk in the comments for the question, but the tech behind this script is Asp.Net MVC ViewModel object decorated with Data Annotations ([Required] in my login case), which is passed to a View and displayed with the following (only included relevant bits unless more is required).

@using (Html.BeginForm())
{
    ...
    <div id="errors"></div>
    @Html.ValidationSummary(true, "Sign in was unsuccessful", new { @class = "alert alert-block alert-error" })
    <div id="laatikko" class="well">
        <div class="control-group">
        <label for="kayttajaTunnus" class="control-label">@Kaannokset.Yhteiset.Sähköposti</label>
        <div class="controls">
            @Html.TextBoxFor(m => m.kayttajaTunnus)
            @Html.ValidationMessageFor(m => m.kayttajaTunnus, null, new { @class = "help-inline" })
        </div>
    </div>
    <div class="control-group">
        <label for="salasana" class="control-label">@Kaannokset.Yhteiset.Salasana</label>
        <div class="controls">
            @Html.PasswordFor(m => m.salasana)
            @Html.ValidationMessageFor(m => m.salasana, null, new { @class = "help-inline error" })
        </div>
    </div>
    <input id="signIn" class="btn btn-primary" data-loading-text="Searching for user..." type="submit" value="Sign In" />
}
like image 149
Miika L. Avatar answered Nov 11 '22 20:11

Miika L.


Miika's answer is spot on. The only thing I'm going to add to it is making it work for when the user actually corrects the errors on the page. To do, you'll need to override MVC's validation summary code to also remove the .error class from the .control-group. Here's Miika's code with this added to it:

$(function() {
    var validator = $('form').data('validator');
    var aspErrorPlacement = validator.settings.errorPlacement;
    validator.settings.errorPlacement = function (error, element) {
        aspErrorPlacement(error, element);
        if (error.length > 0 && error[0].innerHTML === "") {
            error.closest('div.control-group').removeClass('error');
        }
    };
    $('span.field-validation-valid, span.field-validation-error').each(function () {
        $(this).addClass('help-inline');
    });

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

This should do it for you.

like image 42
George Avatar answered Nov 11 '22 20:11

George


This place in ASP.NET MVC is really how to say... broken?

I've looked at proposed solutions and I haven't found one I like, so I wrote my own.

There are two problems:
1) you need to override how highlighting/unhighlighting is performed
2) ok, second problem is because of the first problem and it exists only if you're using jquery.validation.unobtrusive.js. Thing is, that you can't override highlighting/unhighlighting using setDefaults method in jquery.validate because of the way jquery.validation.unobtrusive.js works.

So solution is this:

(function ($) {
  $.fn.bootstrapifyValidation = function () {
    var caller = this;
    function boostrapHighlight(element) {
        $(element).closest(".control-group").addClass("error");
        $(element).trigger('highlated');
    };

    function boostrapUnhighlight(element) {
        $(element).closest(".control-group").removeClass("error");
        $(element).trigger('unhighlated');
    };

    caller.each(function (i, o) {
        var settings = $(o).data('validator').settings;
        settings.highlight = boostrapHighlight;
        settings.unhighlight = boostrapUnhighlight;
    });

    caller.find("div.validation-summary-errors").addClass("alert alert-block alert-error");
 }
})(jQuery)

$(function () {
   $('form').bootstrapifyValidation();
})
like image 1
Giedrius Avatar answered Nov 11 '22 19:11

Giedrius