jquery validate plugin on dynamic form inputs not working - javascript

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.

Related

Add/remove jQuery Validation rule based on Ajax request

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();
});

Select2 change input name if tag is being submited

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 :)

jquery validate input array and passing dynamic values

I'm trying to validate a group of input arrays using jquery validator plugin. I'm having problems understanding how to pass another element into the validation.
My code so far:
$('#edit-fixtures').validate({
rules: {
"player_a[]": {
required: true,
uniqueMatch: function () {
return $(this).next('.player').val();
},
},
"player_b[]": {
required: true,
uniqueMatch: function () {
$(this).closest('.player').val();
},
},
}
});
My input elements are a series of paired select boxes named player_a[] player_b[] There are about 40 pairs. Each pair should be unique and that's what i'll be validating.
I'm trying to pass the value of the nearest player_b to the changed player_a and vice versa.
I have a change method to validate on each change:
$(".player").change(function () {
var check = $(this).valid();
console.log("validation:", check);
});
I'm still working on the validation method but cant seem to get the parameters to the method correctly.
Is there a way of doing this?
uniqueMatch: [$item1, $item2, ....]
$.validator.addMethod('uniqueMatch', function(value, element, parameterValue) {
var item1Value = $(parameterValue[0]).val();
//and so on...
//Based on values, you return true or false;
//Voila!
}

Select2 Event for creating a new tag

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.

Add Same Rule Multiple Fields

I'm trying to add the same rules to html input elements with this naming convention:
name="elements[1]"
name="elements[2]"
I'm using jQuery and jQuery Validation Plugin:
var elements = $("#elementsFieldset :input");
$.each(elements, function(i, element) {
element.rules('add', {
required: true,
number: true
});
But I'm afraid that element is not the kind of object jQuery expects for adding rules.
I'm receiving:
Uncaught TypeError: Object #<HTMLInputElement> has no method 'rules'
Many thanks for any help.
Use $(this) instead of element.
element is HTML JavaScript Object.
to add rules you need jQuery Object i.e $(this)
var elements = $("#elementsFieldset :input");
$.each(elements, function(i, element) {
$(this).rules('add', {
required: true,
number: true
});
or even better
var elements = $("#elementsFieldset :input");
elements.each(function(){
$(this).rules('add', {
required: true,
number: true
});
Updated
Below code works for one element only if you want to apply rule for more than one element use .each() as used in above example.
$("#elementsFieldset :input").rules("add", {
required:true,
number:true
});
Read jQuery Validation Plugin - adding rules that apply to multiple fields commented by Sparky
jQuery Validation Plugin
Try this,
$.each(elements, function(i, element) {
$(this).rules('add', {// use $(this) instead of element
required: true,
number: true
});
or try it simply,
$("#elementsFieldset :input").rules("add", {
required:true,
number:true
});
You can add rule on a class See jQuery Validation using the class instead of the name value

Categories