I'm trying to resolve this issue but no matter what I try (based on several suggestions solutions found here as well), I can never make it work.
I would like the Jquery validation plugin to validate automatically all the generated fields from a form. My problem is that it will only work on the first generated field; the validation of the subsequent ones will just be a duplicate of the first.
Here's the pertinent html code:
<form class="someFormClass" method="post">
<span>
<input class="calendarName" name="description" value="<?= value_from_php ?>">
<input class="calendarName" name="description" value="<?= value_from_php ?>">
</span>
</form>
And here's the jQuery validation code:
$(function () {
$('form').each(function () {
$(this).validate({
errorElement: "div",
rules: {
description: {
required: true,
remote: {
url: "calendar/calendar_available/",
type: "post",
data: {
name: function () {
return $(".calendarName").val();
}
}
}
}
},
messages: {
description: {
required: "Description field can't be blank !",
remote: "This calendar already exists."
}
}
});
});
So, as stated, the plug-in behaves properly for the first field. But if I check the values posted in Chrome's Network, the "name" key created in the jQuery validation will always send the value of the first input.
I tried many things (trying to implement on more level of ".each" method in the validation, trying to generate dynamically a specific id for each field to point on (instead of a class), trying to modify the plugin code as suggested here (How to validate array of inputs using validate plugin jquery), but it didn't work.
I think there's something I don't grasp about the logic here.
UPDATE :
So, one of the reasons of my problem is that jQuery validation absolutely requires input with different names. See : Jquery Validation with multiple textboxes with same name and corresponding checkboxes with same name
So, I made a script to generate a different name for each input with the intention to dynamically create validation rules based on those names, following this suggestion : https://stackoverflow.com/a/2700420/3504492
My validation script now look like this :
$(function() {
var rules = new Object();
var messages = new Object();
$('input[name*=description_]:text').each(function() {
var currentName = $("input[name="+this.name+"]").val();
rules[this.name] = {
description: {
required: true,
remote: {
url: "calendar/calendar_available/",
type: "post",
data: currentName
}
}
},
color: {required: true}
};
messages[this.name] = {
description: {
required: "Description field can't be blank !",
remote: "This calendar already exists."
},
color: {required: "Color field can't be blank !"}
};
});
$('form').each(function () {
$(this).validate({
errorElement: "div",
rules: rules,
messages: messages
});
}) });
This almost works. Almost because if I limit the rules et messages to the required keys, it will display the validation each field (if I add the specific name to the message string, it will display on the proper field). But with a most complex rule like mine (with a remote key containing various keys for instance), I get a " Cannot read property 'call' of undefined. Exception occurred when checking element , check the 'description' method." error in the Console.
My guess is that the "description" declaration in the "rules" definition should be dynamic too (the current "name" field being visited).
Any suggestion?
Related
I am using sails.js 1.0 with vue.js and want to create a dynamic form that contains a dynamic amount of inputs based on the user's preference. So the user should be able to add another input, type in the data and send the complete form with the dynamic amount of data.
My form looks like this:
<ajax-form action="addStuff" :syncing.sync="syncing" :cloud-error.sync="cloudError" #submitted="submittedForm()" :handle-parsing="handleParsingForm">
...
<input class="form-control" id="input1" name="input1" type="text" :class="[formErrors.password ? 'is-invalid' : '']"
v-model.trim="formData.input1" placeholder="Input #1" autofocus>
...
<ajax-button type="submit" :syncing="syncing" class="btn btn-dark">Save changes</ajax-button>
</ajax-form>
The action addStuff in sails looks like this:
module.exports = {
friendlyName: 'Do some stuff',
description: 'Do some stuff with the form data.',
inputs: {
input1: {
description: 'The first input.',
required: true
}
},
fn: async function (inputs, exits) {
// Do some stuff with the inputs
return exits.success();
}
};
I know that normally I would be able to create a dynamic form using vue.js by
setting the data of the Vue instance to an array
creating a two-way-binding
implementing a v-for loop in the form, that then creates an input for every element in the data object
modifying this array by inserting a new element in the array every time the user wants to add another input.
But with sails and this ajax-form, I do not know how to access the vue instance and the data element of it and how to make this also dynamic in the action. Obviously the input would need to contain an array.
How would it be possible to achieve such a dynamic form?
I figured out the missing part. Sails.js is using parasails which is built on top of vue.js.
When generating a new sails page using the sails generator sails new test-project, there is also a contact form generated which also contains the necessary code which can be adapted for this purpose.
That contact form basically consists of
The .ejs page (=the html code that renders the form) in views/pages
The contact.page.js client-side script in assets/js/pages
The server side controller deliver-contact-form-message.js in api/controllers
In the client-side script, the initial formData can be set:
parasails.registerPage('maindivid', {
// ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗
// ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣
// ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝
data: {
// Main syncing/loading state for this page.
syncing: false,
// Form data
formData: { /* … */ },
// For tracking client-side validation errors in our form.
// > Has property set to `true` for each invalid property in `formData`.
formErrors: { /* … */ },
// Server error state for the form
cloudError: '',
// Success state when form has been submitted
cloudSuccess: false,
},
...
as well as methods etc.
It follows a similar structure than plain vue.js.
To achieve what I was trying to do I added a field as array to the formData
formData: {
myinputs: [
{
key: '',
value: ''
}
]
},
Then I bound that in the .ejs file:
<div class="form-row" v-for="(filter, index) in formData.mypinputs">
<input class="form-control form-control-sm" type="text" :class="[formErrors.password ? 'is-invalid' : '']"
v-model.trim="formData.myinputs[index].key" placeholder="My field">
<button type="button" class="btn btn-secondary btn-sm" #click="addFilterForm">add field</button>
</div>
And finally added a method to the client-side script in contact.page.js (or your name) that gets called when the user clicks the "add field" button.
methods: {
addFilterForm: function() {
this.formData.myinputs.push({
key: '',
value: ''
});
},
Because of the two way binding, as soon as an element is added to the array formData.myinputs, another input is created and added to the DOM.
I have written a schema but it does not seem to be validating as I was expecting. I'm assuming there is something wrong with my schema syntax but cannot figure it out. I expect not to see error messages for title or target until fundraiser is complete since they are only required if fundraiser is completed. I've tried many combinations but none of them are working as expected, these two are the closest I've come to what I need.
Schema attempt one: shows 4 error messages, 3 required errors and 1 error saying data should match "then" schema.
const schema = {
required: ['fundraiser'],
if: {
properties: {
fundraiser: { type: 'string' },
},
},
then: {
required: ['title', 'target'],
},
errorMessage: {
required: {
fundraiser: 'Please select an option',
title: 'Please enter a title',
target: 'Please enter a target',
},
},
};
Schema attempt two: shows 2 error messages, 1 required error and 1 error saying data should match "then" schema which is correct but then when I complete fundraiser valid becomes true which is when I expect to then see required errors for title and target. Also no errors have my defined custom error messages.
const scema = {
if: {
properties: { fundraiser: { minLength: 2 } },
then: { required: ['title', 'target'] },
},
then: { required: ['fundraiser'] },
errorMessage: {
required: {
fundraiser: 'Please select an option',
title: 'Please enter a title',
target: 'Please enter a target',
},
},
};
I am pretty sure that I am doing something wrong with my schema but it is not clear from the documentation how to use if/then in combination with custom error messages using ajv-errors. Any help would be greatly appreciated! Thanks!
The problem with the first schema is that subschema inside “if” is valid, unless fundraiser property is present and not a string. It would probably work as you expect if you add type: 'object' to the root schema and move required inside “if” subschema.
The problem with the second subschema is that the first “then” that has no “if” in the same schema object is ignored (unless you are using ajv-keywords that implemented if/then/else somewhat differently from how it is defined in draft-07 of JSON Schema spec) and the subschema inside “if is valid even if fundraiser property is absent and the second “then” can only pass if fundraiser is present.
I've been struggling to get this field validation to work. I'm using the JS validation for bootstrap from http://formvalidation.io/ and I've examined http://formvalidation.io/settings/ but nothing I've tried is working.
The field needs to validate a number input on a dynamically generated field using Razer C#, and the form is built to submit multiple models, therefore my name attribute is values[#i].Rating for each element that is generated, where i is an integer that is incremented in a loop.
The validation must make sure the client enters a number between 1 and 4 (inclusive), and if it is not a number between 1 and 4, it must show an error message such as "Please enter a number between 1 and 4". Here is my code, I first tried it with HTML attributes:
<input style="text-align: center" type="number" data-fv-between-min="1" data-fv-between-max="4" data-fv-between-inclusive="true" data-fv-between-message="Please enter a rating between 1 and 4" name="values[#i].Rating" class="form-control" />
but this didn't work, so I tried the javascript route with:
$(document).ready(function () {
$('#newTSRForm').formValidation({
framework: 'bootstrap',
fields: {
selector: '[type="number"]',
input: {
validators: {
between: {
min: 1,
max: 4,
message: 'Please enter a value between 1 and 4'
}
}
}
}
})
});
but my syntax is probably wrong or my thinking is incorrect. I also tried
$(document).ready(function () {
$('#newTSRForm').formValidation({
framework: 'bootstrap',
fields: {
'values[]': {
validators: {
between: {
min: 1,
max: 4,
message: 'Please enter a value between 1 and 4'
}
}
}
}
})
});
But this doesn't work either. I have made sure my set up is correct so the problem is simply syntax or plausability. Can anybody advise?
¿ Did you look at http://formvalidation.io/examples/validating-field-special-name/ ?
I think you have to add every single field with the AddField method of the Plugin.. Adding dynamic field
This question already has answers here:
JQuery.validate - one rule on blur only; the rest should be normal?
(2 answers)
Closed 8 years ago.
I am trying to do a jquery remote validation to see if a name is unique or not, but i do not want to do remote validation on every single onkekup event, however i would like to do this on blur event(when user leaves the textbox). but with current code i have below, it fires up after 2nd character is pressed. i would like to continue to have rest of the rules fire on onkeyup like required and minlength and rules for other elements.
is there not a property to control this behavior, just for single rule? i noticed a set default that does for entire form.
elem.validate({
ignore: "",
rules: {
name: {
required: true,
minlength: 2,
maxlength: 60,
remote: {
url: "/api/IsUniqueName",
onkeyup: false,
type: "get",
contentType: "application/json",
data: {
name: function () {
return elem.find('input[name^=Name]').val();
}
},
headers: {
RequestVerificationToken: Indexreqtoken
},
}
},
...
You cannot put the onkeyup option inside of the remote rule... that's not how the remote method works. The remote method can only accept the same options as jQuery .ajax() and nothing else.
However, you cannot restrict or control the triggering events on a "per rule" basis. These events are captured for the whole form or individually on each field, they can not be confined to a specific rule.
If you want to restrict the plugin's onkeyup function to certain fields, then you would use a conditional within the onkeyup option...
$('#myForm').validate({
onkeyup: function(element, event) {
if ($(element).attr('name') == "name") {
return false; // disable onkeyup for your element named as "name"
} else { // else use the default on everything else
if ( event.which === 9 && this.elementValue( element ) === "" ) {
return;
} else if ( element.name in this.submitted || element === this.lastElement ) {
this.element( element );
}
}
},
ignore: [], // <- note the proper format for the "ignore nothing" setting.
rules: {
name: {
required: true,
minlength: 2,
maxlength: 60,
remote: {
url: "/api/IsUniqueName",
....
EDIT:
Quote OP:
"is there not a property to control this behavior, just for single rule?"
No, the triggering events cannot be controlled on a "per rule" basis. They can only be controlled for the whole form OR for a specific field, as I've shown above.
https://stackoverflow.com/a/21313848/594235
I'm using the jQuery Validation plugin and i've started to group some of my fields together:
groups: {
fullName: "myFirstName myLastName"
},
I've also added the fields to the rules section so that they are validated:
rules: {
myFirstName: {
required: true
},
myLastName: {
required: true
}
},
This works great and produces an error of "This field is required" for the group.
My question lies with custom error messages. I have the following setup:
messages: {
fullName: "Please enter both your first name and your last name"
}
Unfortunately the custom error doesn't show, only the generic one.
Does anyone have any ideas?
You have to use errorPlacement for this, and the message should be the same on both, for example:
messages: {
myFirstName: { required: "Please enter both your first name and your last name" },
myLastName: { required: "Please enter both your first name and your last name" }
}
Then, assuming they have the same IDs here, your errorPlacement option would look like this:
errorPlacement: {
var n = element.attr("name");
if (n == "myFirstName" || n == "myLastName")
error.insertAfter("#myLastName");
else
error.insertAfter(element);
}
The group itself has no message, it's just telling the plugin that they share a message label.