Adding a validator to my form:
jQuery.validator.addMethod('whatever', function(val, el) {
// whatever goes here
}, 'A maximum of ' + $('#my_id_here').val() + ' categories can be selected.');
This doesn't fly. I always get undefined. Is this a good, simple way to do this?
Thanks
Something like this:
$(document).ready(function()
{
jQuery.validator.addMethod("validateCountries", function(value, element) {
alert('s');
return this.optional(element) || /^\d{3}-\d{3}-\d{4}$/.test(value);
});
// add the validation rule
$("#form1").validate();
$("#lbCountries").rules("add", { validateCountries:true });
});
Inside the Add method you can perform your validation!
UPDATE 1:
With dynamic text you will loose the error messages displayed. Here is a way to tackle that issue:
// add the validation rule
$("#form1").validate(
{
messages: { lbCountries: "please specify the countries" }
}
);
The lbCountries is a ListBox control.
UPDATE 2:
You can attach another rule attribute with the rule as shown below:
$("#lbCountries").rules("add", { validateCountries:true, noOfSelectedItems:3 });
Now, you can check for the rule when the event is fired:
$("#lbCountries").rules().noOfSelectedItems; // this will return 3
Related
I'm having a problem changing a specific rule from jQuery Validation based on an Ajax Get request.
I have one form composed by one parent form and two child forms that are updated by Jquery.post request. The two child forms, when submitted, updates a counter that is saved into their respectives hidden inputs, and the validation upon the condition that the counters needed to have at least 1 item registered for both worked fine...
until the rule get more complex.
Now, depending on the value of the items of the first child form saved, the "min" rule has to be activated or not.
Example: the items have code values between 200 and 500; if there's at least one item registered with a code above or equal 300 the "min" rule has to be applied, otherwise it's not needed. The problem is that it has to be resolved dynamically, because if the items that have code >= 300 are removed from first child form list, or if there's not any item with that code value and then one of them is saved, the validation rules have to be updated.
I´ve tried updating rule on the return of the $.post success function, it only add the rule, never remove it at all:
$.get('{url of the updating form}', function(data){
if (data >=300) {
$('#counter_form_child_2').rules('add', { min: 1 });
} else {
$('#counter_form_child_2').rules('remove'); //removes all rules for this input
}
});
Tried to make a query that returns bool (true or false) searching if there's any item with code >=300 and putting it into another hidden field:
//Code inside the js function that returns the boolean value
$.get('{url of the updating form}', function(data) {
$('#item_above_300').val(data); //puts value into hidden field
});
//Code inside form validation rules
$("#parentForm").validate({
ignore: ':hidden:not(#counter_form_child1, #counter_form_child1),
rules : {
(...)
counter_child_form1: { min: 1 },
counter_child_form2: {
min: { param: 1,
depends: function(element) {
return $('#item_above_300').val() === 1;
}
}
}
}
});
I need some help, because I'm exausted of trying several alternatives and nothing works. Thanks a lot!
In the end, the problem wasn't on the rules actually...
Testing the valid fields using showErrors, I could debug and found out that the hidden field was updating correctly and the error counted out:
showErrors: function(errorMap, errorList) {
var submitted = true;
if (submitted) {
var summary = "Precisa corrigir os seguintes erros: <br/>";
$.each(errorMap, function(name, value) {
summary += " * (" + name + + value + "<br/>";
});
$("#msg_aviso").html(summary);
submitted = false;
}
this.defaultShowErrors();
}
Then I found out that the problem was at the errorMessage displaying.
And ONLY at the counter_child_form2 message.
So, after researching at some questionings here at Stack Overflow I found that the solution was reset the DIV that displays that specific error message every submit form event. And... voilá, it worked!
$('#parentForm').click(function(){
$("#counter_child_form2_error .error").html('');
$("#parentForm").submit();
});
Consider this application of the jQuery validation plugin:
(function($) {
'use strict';
$('form[data-behavior="validate"]').validate({
errorElement: 'span',
ignore: ':hidden, .select-dropdown',
normalizer: function(value) {
if (!value) value = '';
if ($(this).is('[data-currency-mask]')) {
return value.replace(/\$/g, '').replace(/,/g, '');
}
return value;
},
highlight: function(element) {
$(element).addClass('invalid');
$(element.form).find('label[for=' + element.id + ']').addClass('invalid');
},
unhighlight: function(element) {
$(element).removeClass('invalid');
$(element.form).find('label[for=' + element.id + ']').removeClass('invalid');
}
});
})(jQuery);
This custom validator adds/removes the error class "invalid" to/from both the element and its label. The result looks like this (where Materialize.css is used):
There is some code repetition in the highlight and unhighlight functions, which I'd like to eliminate; in addition, it seems like I could make use of the errorClass attribute (cf. https://jqueryvalidation.org/validate/) instead of hard-coding 'invalid' everywhere.
I've tried setting errorClass: 'invalid' in the object passed to .validate(), and then using errorClass instead of 'invalid' in the highlight and unhighlight methods, but this appears not to work. How can I refactor this code?
I don't have enough reputation to comment because people won't flame my answers or what ever it takes to get reputation.
But, the first thing I notice is
if (!value) value = '';
should be
if (!value) { value = ''; }
which could also be initialized with
value = value || '';
or, depending what version of ECMAscript you're using, you could even save a line of code and initialize it in the parameters
normalizer: function(value = '')
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters
So I have the following select2:
productFamilySelect.select2({
tags: true
});
By default the name of the associated select element is product_family_id, so is there a way to change the name of the input to lets say product_family_name, if selected value if one that user entered? This is so, that I could in the backend for sure distinguish between an already existing value, and one that user thought of. Checking by id in the database does not really suit, as this value could actually be numeric in on itself.
After some digging into select2 custom events I found a way:
firstly add createTag callback like so:
productFamilySelect.select2({
tags: true,
createTag: function (params) {
var term = $.trim(params.term);
if (term === '') {
return null;
}
return {
id: term,
text: term,
newTag: true
}
}
});
Then, add the following listener:
productFamilySelect.on('select2:select', function (e) {
if (e.params.data.newTag === true) {
$(this).attr('name', 'product_family_name');
} else {
$(this).attr('name', 'product_family_id');
}
});
Seems a bit hacky, since it is outside the config of the actual select2 config, but well it dos the job :)
I'm using the jQuery Select2 (v4) plugin for a tag selector.
I want to listen for when a new tag is created in the select element and fire an ajax request to store the new tag. I discovered there is the createTag event but this seems to fire every time a letter is entered into the select2 element. As shown in my fiddle: http://jsfiddle.net/3qkgagwk/1/
Is there a similar event that only fires when the new tag has finished being entered? I.e. it's enclosed by a grey box enclosing it.
I can't find any native method unfortunately. But if you're interested in simple "workarounds", maybe this get you closer:
$('.select2').select2({
tags: true,
tokenSeparators: [",", " "],
createTag: function (tag) {
return {
id: tag.term,
text: tag.term,
// add indicator:
isNew : true
};
}
}).on("select2:select", function(e) {
if(e.params.data.isNew){
// append the new option element prenamently:
$(this).find('[value="'+e.params.data.id+'"]').replaceWith('<option selected value="'+e.params.data.id+'">'+e.params.data.text+'</option>');
// store the new tag:
$.ajax({
// ...
});
}
});
DEMO
[EDIT]
(Small update: see #Alex comment below)
The above will work only if the tag is added with mouse. For tags added by hitting space or comma, use change event.
Then you can filter option with data-select2-tag="true" attribute (new added tag):
$('.select2').select2({
tags: true,
tokenSeparators: [",", " "]
}).on("change", function(e) {
var isNew = $(this).find('[data-select2-tag="true"]');
if(isNew.length && $.inArray(isNew.val(), $(this).val()) !== -1){
isNew.replaceWith('<option selected value="'+isNew.val()+'">'+isNew.val()+'</option>');
$.ajax({
// ... store tag ...
});
}
});
DEMO 2
The only event listener that worked for me when creating a new tag was:
.on("select2:close", function() {
(my code)
})
This was triggered for new tags and selecting from the list. change, select2:select, select2:selecting and any others did not work.
One more simple check will be this based on the difference in the args of the event .....
While I was dealing with this situation, I had seen this difference; that when the new element is created the event args data does not have an element object but it exists when selecting an already available option...
.on('select2:selecting', function (e) {
if (typeof e.params.args.data.element == 'undefined') {
// do a further check if the item created id is not empty..
if( e.params.args.data.id != "" ){
// code to be executed after new tag creation
}
}
})
Another workaround. Just insert it to the beginning:
}).on('select2:selecting', function (evt) {
var stringOriginal = (function (value) {
// creation of new tag
if (!_.isString(value)) {
return value.html();
}
// picking existing
return value;
})(evt.params.args.data.text);
........
It relies on underscore.js for checking if it's string or not. You can replace _.isString method with whatever you like.
It uses the fact that when new term is created it's always an object.
I've a form where I'm having some fields and then if needed user can add more fields of same type. Im using http://jqueryvalidation.org/ validate plugin to validate fields.
As I read somewhere jquery validate plugin requires unique names to fields for validating them. So i'm naming each field uniquely. First I hoped that validate plugin will take care of dynamically added element's validation if I add rules using classes. But it turns out it does not.
So even if name of each field is unique, validate plugin validates only first input which was rendered initially.
I even tried using $.clone() in hope that it'll take care of all event bindings. But it did not worked for me. So I moved to underscore to repeat the markup as there are number of fields and I don't want to write templates in JS and name accordingly.
I can't find a solution to this and stuck here. Can't more on until this issue is resolved.
Here's JS that I've written.
$("#work_form").validate();
$(".work_emp_name").rules("add", {
required: true
});
_.templateSettings.variable = "element";
var tpl = _.template($("#form_tpl").html());
var counter = 1;
$("form").on("click", ".add_employer", function (e) {
e.preventDefault();
var tplData = {
i: counter
};
$("#word_exp_area").append(tpl(tplData));
counter += 1;
});
Please find markup in fiddle set up.
example and code set up here
When using one of the methods from this plugin, like .rules(), and targeting more than one element, like a class, you must also use the jQuery .each() method.
$('.work_emp_name').each(function () {
$(this).rules("add", {
required: true
});
});
And you cannot use .rules() on elements that don't yet exist in the DOM. Simply move the .rules() method to inside the function that creates your new inputs.
$("form").on("click", ".add_employer", function (e) {
e.preventDefault();
var tplData = {
i: counter
};
$("#word_exp_area").append(tpl(tplData));
counter += 1;
$('.work_emp_name').each(function () {
$(this).rules("add", {
required: true
});
});
});
Working DEMO: http://jsfiddle.net/Yy2gB/10/
However, you can make it more efficient by only targeting the one new field, instead of all fields with the work_emp_name class.
$("form").on("click", ".add_employer", function (e) {
e.preventDefault();
var tplData = {
i: counter
};
$("#word_exp_area").append(tpl(tplData)); // <- add new field
$('input[name="work_emp_name['+counter+']"]').rules("add", { // <- apply rule to new field
required: true
});
counter += 1;
});
Working DEMO: http://jsfiddle.net/Yy2gB/11/
Both of my examples above are for adding rules to the dynamically created fields. You'll still need to declare any rules for your static fields upon dom ready as follows...
$("#work_form").validate({
rules: {
"work_emp_name[0]": {
required: true
}
}
});
Returns the validations rules for the first selected element or
Adds the specified rules and returns all rules for the first matched element. Requires that the parent form is validated, that is, $( “form” ).validate() is called first or
Removes the specified rules and returns all rules for the first matched element.
more info
function addRule(id){
$("[name='work_emp_name["+id+"]']").rules("add", {
required: true
});
}
$("#work_form").validate();
addRule(0);
_.templateSettings.variable = "element";
var tpl = _.template($("#form_tpl").html());
var counter = 1;
$("form").on("click", ".add_employer", function (e) {
e.preventDefault();
var tplData = {
i: counter
};
$("#word_exp_area").append(tpl(tplData));
addRule(counter);
counter += 1;
}); here
That's because jQuery Validation only validates the first occurrence of the array currently.
You can check my commit on the plugin that will just work fine on any occurrence of the named array.