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!
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" />
}
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.
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();
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With