We recently decide to migrate to jquery 1.9.1
and since our project is in ASP.NET MVC 3
, it has the jquery.validate
and jquery.validate.unobtrusive
. Everything worked fine and the default integration between these scripts and MVC 3 validation through property atributes were acting just fine.
However since the update, we also had to update the validation scripts and when we did that, those 'on the fly' added rules stopped working. But what's more bizarre is that it only happens on some properties. On others, through the $(form).validate({//things to validate})
the rules simply apply.
Let me give you some code to explain it better. Here's the ViewModel properties (it's a reduced example):
[DataType(DataType.Password)]
[Required(ErrorMessage = "*Required Field")]
[Remote("ValidatePassword", "Validator", AdditionalFields = "User")]
public string SenhaAnterior { get; set; }
[HiddenInput]
public int VerificacaoSeguranca { get; set; }
Here's the view
@using (Html.BeginForm("...", "...", null, FormMethod.Post, new { @id = "formMSenha" }))
{
<div id="container">
@Html.HiddenFor(model => model.VerificacaoSeguranca, new { @id = "hdSeguranca" })
@Html.ValidationMessageFor(model => model.VerificacaoSeguranca)
<div>
<label>
Senha anterior:
@Html.PasswordFor(model => model.SenhaAnterior, new { @id = "txtSenhaAnterior" })
@Html.ValidationMessageFor(model => model.SenhaAnterior)
</label>
</div>
</div>
}
And the script
//Even if try this, it still doesn't work
$('#formMSenha').validate({
rules: {
hdSeguranca: {
min: 4
}
},
messages: {
hdSeguranca: 'Your password lacks security. Try harder'
}
});
//Since this is a partial view, i have to parse the new added form so the validation rules apply
$.validator.unobtrusive.parse($("#formMSenha"));
//Minimum security level
$('#hdSeguranca').rules('add', { min: 4, messages: { min: 'Your password lack security. Try adding more numbers, letters ou symbols.'} });
Before the update, the new add rule worked but now it doesn't. It's like the new rule never gets parsed by the validator or as it doesn't recognize it. But what's bizarre is if i do this
('#formMSenha').validate({
rules: {
txtSenhaAnterior: {
min: 4
}
},
messages: {
hdSeguranca: 'New test'
}
});
$('#txtSenhaAnterior').rules('add', { min: 4, messages: { min: 'Newer teste'} });
The validation applies! I have absolutely no idea why.
EDIT
As suggested by @Sparky, i'm showing the rendered HTML of this PartialView (it's jquery dialog), with some little modifications.
<div id="msenhaContainer">
<form method="post" id="formMSenha" action="..." novalidate="novalidate"> <h2>
Atualize sua senha para uma senha complexa</h2>
<div id="campos">
<input type="hidden" value="0" name="VerificacaoSeguranca" id="hdSeguranca" data-val-required="The VerificacaoSeguranca field is required." data-val-number="The field VerificacaoSeguranca must be a number." data-val="true">
<div>
<label>
Senha anterior:
<input type="password" name="SenhaAnterior" id="txtSenhaAnterior" data-val-required="*Campo obrigat&#243;rio" data-val-remote-url="/Validator/ValidarSenhaAnterior" data-val-remote-additionalfields="*.SenhaAnterior,*.Usuario" data-val-remote="&#39;SenhaAnterior&#39; is invalid." data-val="true" class="input-validation-error">
<span data-valmsg-replace="true" data-valmsg-for="SenhaAnterior" class="field-validation-error"><span for="txtSenhaAnterior" class="">*Campo obrigatório</span></span>
</label>
</div>
<div>
<label>
Nova Senha: <input type="password" name="SenhaNova" maxlength="18" id="txtSenhaNova" data-val-required="*Campo obrigat&#243;rio" data-val="true" class="valid">
<span data-valmsg-replace="true" data-valmsg-for="SenhaNova" class="field-validation-valid"></span>
</label>
</div>
<div>
<label>
Nova Senha Confirmação: <input type="password" name="SenhaNovaConfirmacao" maxlength="18" id="txtSenhaNovaConf" data-val-required="*Campo obrigat&#243;rio" data-val-equalto-other="*.SenhaNova" data-val-equalto="As senhas n&#227;o s&#227;o as mesmas" data-val="true" class="valid">
<span data-valmsg-replace="true" data-valmsg-for="SenhaNovaConfirmacao" class="field-validation-valid"></span>
</label>
</div>
<br>
<label>
Força da Senha</label>
<div id="progressoSenha" class="ui-progressbar ui-widget ui-widget-content ui-corner-all" role="progressbar" aria-valuemin="0" aria-valuemax="6" aria-valuenow="2">
<div class="ui-progressbar-value ui-widget-header ui-corner-left" style="display: block; width: 33%; background: none repeat scroll 0% 0% rgb(209, 125, 14);"></div></div>
<span data-valmsg-replace="true" data-valmsg-for="VerificacaoSeguranca" class="field-validation-valid"></span>
<div style="text-align: center" id="descricaoForcaSenha">Fraca</div>
<a id="regrasSenha" href="#" title="Tooltip com as regras aqui!">Regras da senha complexa</a>
</div>
<input type="hidden" name="freebird" data-val-required="If i stay, will still remember me" id="freebird"></form></div>
<script type="text/javascript">
//Xhalent's function
(function ($) {
$.validator.unobtrusive.parseDynamicContent = function (selector) {
//use the normal unobstrusive.parse method
$.validator.unobtrusive.parse(selector);
//get the relevant form
var form = $(selector).first().closest('form');
//get the collections of unobstrusive validators, and jquery validators
//and compare the two
var unobtrusiveValidation = form.data('unobtrusiveValidation');
var validator = form.validate();
$.each(unobtrusiveValidation.options.rules, function (elname, elrules) {
if (validator.settings.rules[elname] == undefined) {
var args = {};
$.extend(args, elrules);
args.messages = unobtrusiveValidation.options.messages[elname];
//edit:use quoted strings for the name selector
$("[name='" + elname + "']").rules("add", args);
} else {
$.each(elrules, function (rulename, data) {
if (validator.settings.rules[elname][rulename] == undefined) {
var args = {};
args[rulename] = data;
args.messages = unobtrusiveValidation.options.messages[elname][rulename];
//edit:use quoted strings for the name selector
$("[name='" + elname + "']").rules("add", args);
}
});
}
});
}
})($);
//DOM ready
$(function () {
//Since this is a test, there's no reason to submit the form to the server
$.validator.setDefaults({
debug: true
});
//Trying to remove the validator to revalidate the form with the new added rule
$("#formMSenha").removeData("validator").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse($("#formMSenha"));
$('#hdSeguranca').rules('add', { min: 4, messages: { min: 'Your password lacks security'} });
//Got this example on Xhalent's blog, but it didn't work either
// $.validator.unobtrusive.parseDynamicContent($('#hdSeguranca'));
$.validator.unobtrusive.parse($("#formMSenha"));
$('#progressoSenha').progressbar({ max: 6, value: 0 });
$('#txtSenhaNova').keyup(function () {
VerifyPasswordStrength($(this).val());
});
$('#regrasSenha').tooltip({ content: function () {
// var texto = $('<div style="display: inline" ></div>');
// texto.html('Regras da senha complexa:');
// texto.append("<ul>").append('<li>').append(
// $('<span>').html('Deve possuir pelo menos 6 caracteres')).insertAfter($('<li>').append('<span>').html('Deve ter ao menos um número')).
// insertAfter($('<li>').append('<span>').html('Deve ter ao menos um caractere especial. Ex:"! @ # $ % &" '));
// return texto;
var textoSenha = $('#descSenha').html();
return textoSenha;
}
});
$('#formMSenha').submit(function () {
$.ajax({
type: 'post',
url: '...',
data: $('#formMSenha').serialize(),
dataType: 'json',
success: function (data) {
$.growlUI('Sucesso', 'Sucesso', 'Flawlessly done!');
setTimeout(function () { window.location.replace('/') }, 2000);
}
});
return false;
});
}); //JQUERY END
function VerifyPasswordStrength(password) {
//Removed the security code, but what it does is validate the input
//to check if the user abide to the safety rules
//When everything is done, it assigns a value to the hidden var
//The mininum score required is 4. So if the user don't hit 4 points
//it can't let him proceed and submit the form
$('#hdSeguranca').val(passwordScore);
var progressbar = $("#progressoSenha");
var progressbarValue = progressbar.find(".ui-progressbar-value");
var cor = '#9c9999';
switch (judite) {
case 1:
cor = '#790f0f'; //red
break;
case 2:
cor = '#d17d0e'; //orange
break;
case 3:
cor = '#e1e40b'; //yellow
break;
case 4:
cor = '#129f0a'; //green
break;
case 5:
cor = '#0768c7'; //blue
break;
case 6:
cor = '#92dae8'; //brighter blue
break;
}
progressbarValue.css({ "background": '' + cor });
$('#progressoSenha').progressbar("option", "value", passwordScore);
$('#descricaoForcaSenha').html(desc[passwordScore]);
}
</script>