Add/remove jQuery Validation rule based on Ajax request - javascript

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

Related

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 plugin on dynamic form inputs not working

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.

Alfresco Share client-side synchronous Form validation

I have an Alfresco Share client-side Form in a registration scenario and I want to validate if the chosen username is taken.
Can I add a Alfresco forms validator in a synchronous way?
So far my form goes something like this:
this.widgets.saveForm = new Alfresco.forms.Form(this.id + "-form");
this.widgets.saveForm.addValidation(Dom.get(this.id + "-username"), this.validateUsername, me, "blur", this.msg("validation-hint.username-taken"));
But this.validateUsername needs to make an Alfresco.util.Ajax.request to a repo-side web service which checks availability for the chosen username. So basically, by the time the response is here, my original validateUsername method is long-finished, returning false (likely).
My progress so far is to disable the submit button (that is why I am passing "me" to the validation handler), and have success/failure callbacks enable it if the username is fine.
What would be a decent way to make a synchronous validator?
A side question would be if there is a better way to set the scope of the validation handler to "this", as opposed to passing me (this one works too, this is just to make sure I am not missing a better way).
This is a snippet of the create-site form. It does the same and checks if the shortname is already present and shows an error if it's taken.
createSiteForm.doBeforeFormSubmit =
{
fn: function()
{
var formEl = Dom.get(this.id + "-form");
formEl.attributes.action.nodeValue = Alfresco.constants.URL_SERVICECONTEXT + "modules/create-site";
this.widgets.okButton.set("disabled", true);
this.widgets.cancelButton.set("disabled", true);
// Site access
var siteVisibility = "PUBLIC";
if (this.widgets.isPublic.checked)
{
if (this.widgets.isModerated.checked)
{
siteVisibility = "MODERATED";
}
}
else
{
siteVisibility = "PRIVATE";
}
this.widgets.siteVisibility.value = siteVisibility;
this.widgets.panel.hide();
this.widgets.feedbackMessage = Alfresco.util.PopupManager.displayMessage(
{
text: Alfresco.util.message("message.creating", this.name),
spanClass: "wait",
displayTime: 0
});
},
obj: null,
scope: this
};
// Submit as an ajax submit (not leave the page), in json format
createSiteForm.setAJAXSubmit(true,
{
successCallback:
{
fn: this.onCreateSiteSuccess,
scope: this
},
failureCallback:
{
fn: this.onCreateSiteFailure,
scope: this
}
});
So this is the client side JavaScript file create-site.js which does the ajax call just before the submit.
My workaround solution is this:
Add a custom validation to the form, and pass the "var me = this" for the validator function to get the scope.
this.widgets.saveForm.addValidation(Dom.get(this.id + "-username"), this.validateUsername, me, "blur", this.msg("validation-hint.username-taken"));
Add a validation handler function which will a. disable the submit button and set the "checking" CSS class to the appropriate form for the user to have feedback. Code snip:
validateUsername: function Reg_validateUsername(el, me) {
var val = this.fieldId.value;
var username = trim(val);
me.widgets.registerButton.set("disabled", true);
Dom.addClass(me.id + "-username-img", "checking");
Dom.removeClass(me.id + "-username-img", "hidden");
Alfresco.util.Ajax.request({
url: "/alfresco/service/slingshot/register/username-available?username=" + username
, method: "GET"
, successCallback: {
fn: me.onUsernameAvailable
, scope: me
}
, failureCallback: {
fn: me.onUsernameTaken
, scope: me
}
});
Write a backend webscript username-available.get that will return success only if the username is free (and valid, even though I have another validator for that).
onUsernameAvailable will set the submit button to enabled again and run validation again (because of other fields) and change the CSS class to "valid".
onUsernameTaken will set the CSS class to "taken".
That's how I ended up doing this.

jQuery Validator - Dynamic Text

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

why is this form still submitting after return false?

I am planning on showing/hiding divs to validate a form.
But the divs only show a split second, and then the form gets submitted...
Any ideas why?
here is the code:
function validateForm() {
var name = nameEmpty(document.getElementById("annonsera_name"));
if (nameEmpty(name)){return false;}
return false;
}
function nameEmpty(fld){
if (fld.value==0) {
document.getElementById("annonsera_nameempty_error").style.display='block';
document.getElementById("annonsera_namenotvalid_error").style.display='none';
document.getElementById("annonsera_name").focus();
return false;
}
else if (fld.value.match(alphaExp)) {
document.getElementById("annonsera_namenotvalid_error").style.display='block';
document.getElementById("annonsera_name").focus();
document.getElementById("annonsera_nameempty_error").style.display='none';
return false;
}
document.getElementById("annonsera_nameempty_error").style.display='none';
document.getElementById("annonsera_namenotvalid_error").style.display='none';
return false;
}
and here is the form:
<form name="annonsera" id="annonsera" method="post" enctype="multipart/form-data" onSubmit="return validateForm();">
It's probably generating an error and therefore never returning anything. Assuming you are using Firefox, have you checked the javascript console?
I see what looks like a problem here, where you call nameEmpty() twice - once with a field, and the other time with a (presumably?) boolean value:
var name = nameEmpty(document.getElementById("annonsera_name")); // Returns boolean
if (nameEmpty(name)){return false;} // Tries to pass boolean back into nameEmpty?
Maybe a bit offtopic, but here goes...
You should really consider JQuery Validation, it's nice, clean and easy to implement. I've done it a few times, and never looked back since. It sure beats the manual validation method like the one you use :)
Check out the example, there really is not that much code to write, to get validation going.
In your example that would be (not tested):
<script>
$(document).ready(function(){
$("#annonsera").validate({
rules: {
annonsera_name: {
required: true,
minlength: 1
}
},
messages: {
annonsera_name: {
required: "You need to write your name",
minlength: jQuery.format("At least {0} characters required!")
}
}
})
});
</script>
There are also a lot of ways of customization through dhtml and css, check out the options.

Categories