after a long research on internet i'm about to give up, let's say you are my last hope. My problem: I'm implementing a timesheet form for my company. This form is dynamic because in a day you can do several activities. The fields (included in a PHP page) are:
Day (text field)
Hours (drop down)
Notes (a text field where the employee can write notes for the day)
All the fields listed are in a row enclosed in a fieldset. On the top of field set i've put a button, clicking it I will add another row with the data listed before. Now, before submitting to backend, I want, of course, put some validation rules which are the following:
Field DAY must be required (it's my key in DB and i've added a DatePicker plugin)
The sum of hours in an entire day can't exceed the 8 hours
I've tried to use Jquery Validate but seems I have two problems:
It can't handle in somehow the arrays of data going to the script php that will write down on DB (for example the days submitted will arrive to backend in an array, I've decided this way because the number of days that can be recorded is not known before submission)
It adds the controls only on first row
I've tried (as I've read in other posts) to add rules after the creation of new row, but, in that case, it works on other fields only if i put the cursor inside, I leave the field blank and then I click outside that field.
I attach my code, any help would be appreciated!!
greetings from Italy.
<script type="text/javascript">
$(document).ready(function() {
var i = 0;
//fadeout selected item and remove
$('.remove').live('click', function() {
$(this).parent().fadeOut(300, function(){
$(this).empty();
return false;
});
});
$('a#add').click(function() {
i++;
var options = '<p>Day <input type="text" id = "Day'+i+'" class = "Day" name="day[]"> </select> hours<select id = "hours'+i+'" class = "hours" name="hours[]"><option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7">7</option><option value="8">8</option></select> Notes <input type="text" id="Note'+i+'" class = "Note" name="note[]"><img src="images\\remove.png" height="20" width="20"></img></p>';
$(options).fadeIn("slow").appendTo('#extender');
});
$('.Day').live('click', function() {
$(this).datepicker('destroy').datepicker({
changeMonth: false,
changeYear: false,
stepMonths: false,
dateFormat: "dd-mm-yy",
showOn:'focus'}).focus();
});
});
</script>
this is where the dynamic fields are appended
<form name="rec_abs" method="post" action = "rec_on_db.php">
<fieldset>
<legend>Timesheet</legend>
<div id="extender"></div>
<p><img src="images\add.png" alt="" border=3 height=20 width=20></img> </p>
</fieldset>
</form>
<input type="submit" value="Send your timesheet"></input><br>
Regarding the fact that your elements are only validated when you change them, you can try using the plugin's onsubmit option:
$("form[name='rec_abs']").validate({
onsubmit:true
});
When it comes to validating multiple fields, I'd suggest adding a class rule to your validation using the addClassRule method.
Define your rule the following way:
$.validator.addClassRules("my-day", {
required: true
});
Then add the my-day class to your day elements.
Regarding the sum of the hours, look into the addMethod method. It enables you to define custom validation rules. Here's an example that checks if a phone number is in the +XXXXXX format (X is a number, + is optional):
$.validator.addMethod("phone", function(value, element) {
// no phone number is a good phone number (the field is optional)
if (value.length == 0) { return true; }
// use a regexp to test the if the value is in the '+XXXXXX..' form
return /^\+?(\d){5}\d+/i.test(value);
}, 'Invalid phone number');
I've managed to get my validation to work on ajax loaded content before, while retaining my script in a separate file using class rules and custom methods.
Thanks for reply Sir Celsius. Now with the first modification you suggested I can validate my form at submit. There is more than this by the way. I modified the code generating the dynamic form as follows:
$('a#add').click(function() {
i++;
var options = ' .... html of the row as before ...';
$(options).fadeIn("slow").appendTo('#extender');
$('#Day'+i).rules('add', {
required: true,
messages: {
required: ""
}
});
$('#Hours'+i).rules('add', {
required: true,
messages: {
required: ""
}
});
});
With these lines I add rules at newly created parts of document. I've put a counter just to make every cell have its own ID, class name remains the same. For my purpose I have to put data in arrays, every type of data has its own vector. Here is the problem. If all the fields have different IDs (OK for HTML), same CLASS (OK for HTML), BUT SAME NAME (ok for HTML but not for Jquery validation), the validation is operated only on the first row! To accomplish the aim I've made a modification to query.validate.js putting this code:
checkForm: function() {
this.prepareForm();
for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
if (this.findByName( elements[i].name ).length != undefined && this.findByName( elements[i].name ).length > 1) {
for (var cnt = 0; cnt < this.findByName( elements[i].name ).length; cnt++) {
this.check( this.findByName( elements[i].name )[cnt] );
}
} else {
this.check( elements[i] );
}
}
return this.valid();
}
replacing the "standard" form
checkForm: function() {
this.prepareForm();
for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
this.check( elements[ i ] );
}
return this.valid();
}
as suggested at link Jquery Validation validate form-array. Now the validation works perfectly. I will work at second part of validation (sum of hours) and I'll let you know! Thank you so much for the moment!
Related
So I need to mask a SSN# input field, lets say the ssn is 123-45-6789, I need to display ***-**-6789 (real time as they enter each digit) but I still need to retain the original value to submit.
I got to the point where I can do that if the user strictly enters the value but it breaks if the user does anything else such as delete, or moving cursor to a random position and adds/deletes a number, copy pasting/deleting, etc. I really don't want to listen to a bunch of events to make this work if thats even possible.
I also tried having a div sit on top of the input field to display the masked ssn while the actual ssn was transparent/hidden behind it but again they lose the functionality of being able to add/delete/select delete/paste in random parts (other then when they start at the end) and also the cursor not totally in sync with the end of the ssn number (asterisk size was the issue). This also broke on some mobile browsers.
I also thought of having two separate input fields, one type password, and one type text sit right next to each other, but again highlighting and deleting/pasting between the two would be an issue.
Ideally if there was something out there to have an input field have two types, part of the value be type password and the rest be type text, that would be fantastic. Btw this is for react js app.
TLDR: Need a fully functional input field that will do password masking on only first 5 digits of ssn and be plaintext for last 4 digits (while having the full plaintext value available for submission).
Thanks!
This might be a little sloppy, but it works as you want it to, is all in one text field, returns the full accurate SSN (despite replacing first 5 values with bullet points), and allows for editing anywhere in the field.
<input type="password" id="ssn" maxlength=9 />
<script>
var ssn = document.getElementById('ssn');
ssn.addEventListener('input', ssnMask, false);
var ssnFirstFive = "";
var secondHalf = "";
var fullSSN = "";
function ssnMask(){
if (ssn.value.length <= 5){
ssn.type = 'password';
}
else{
detectChanges();
secondHalf = ssn.value.substring(5);
ssn.type = 'text';
ssn.value = "•••••";
ssn.value += secondHalf;
fullSSN = ssnFirstFive + secondHalf;
}
}
function detectChanges() {
for (var i = 0; i < 5; i++){
if (ssn.value[i] != "•"){
ssnFirstFive = ssnFirstFive.substring(0, i) + ssn.value[i] + ssnFirstFive.substring(i+1);
}
}
}
</script>
Essentially, every time the input is changed, it checks to see if it matches the first 5 from before, and if it doesn't, it will update the necessary characters.
You can use 3 different fields and make then password fields.
Add a focus handler that changes their type into text and a blur handler that changes them back to password.
You can combine them before submission or on the server.
#ssn1{width:25px;}
#ssn2{width:20px;}
#ssn3{width:35px;}
<input type="password" name="ssn" maxlength=3 id="ssn1" />
<input type="password" name="ssn" maxlength=2 id="ssn2"/>
<input type="password" name="ssn" maxlength=4 id="ssn3"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$('[name="ssn"]').focus(function() {
$(this).attr("type", "text")
});
$('[name="ssn"]').blur(function() {
$(this).attr("type", "password")
});
</script>
You can also write a pass handler to all a full SSN to be pasted in the first field and have all three fields get set.
This is the closest you are going unless you work with a single full text box and give the user the ability to mask and unmask the field.
In production apps, this actually the approach I take:
Masked:
Unmasked:
You can implement you own focus/blur functions to automatically unmask/mask the field as needed.
Achieve this using html data attributes.
i have used the same html tag and store actual value in html tag attribute (data-value) to use later on and store value to display in html tag attribute value.
Function to partial mask input value
function mask_field_value(obj, mask_letters_count=7){
mask_value = $(this).data('mask-value') || '';
unmask_value = $(this).data('unmask-value') || '';
if (obj.value.length <= mask_letters_count){
obj.type = 'password';
mask_value = obj.value;
$(this).data('mask-value', obj.value);
} else {
obj.type = 'text';
unmask_value = obj.value.substring(mask_letters_count);
obj.value = "*".repeat(mask_letters_count) + unmask_value;
$(this).data('unmask-value', unmask_value);
}
$(this).data('value', mask_value + unmask_value);
console.log($(this).data('value'));
}
Add an event on input fields to mask
$(document).ready(function () {
$(document).on('keyup', '.mask_input_display', function () {
mask_field_value(this);
});
});
I'm having issues validating some dynamic content. The closest I have come to finding a similar problem is this:
jquery-validate-is-not-working-with-dynamic-content
My form is a basic form, enter name, email, phone etc. But there's this question "How many passengers?"
This is a select and depending on how many passengers you select, I use jQuery to create more fields based on this amount using this:
$('select.travellers').attr('name','Number of travelers').on('click', function() {
var travellers = this.value; //On change, grab value
var dom = "";
for(var i = 0; i < travellers; i++){ //for 0 is less than travellers
dom += '<label>Full Name</label>';
dom += '<input type="text" name="FullName_'+i+'">';
dom += '<label>Food requirements</label>';
dom += '<select size= "0" name="Food Requiries_'+i+'" tabindex="-1" >
<option value="No pork">No pork</option>
<option value="Halal">Halal</option>
<option value="Food allergies">Food allergies</option>
<option value="Other">Other</option></select>';
}
$('.form_Additional').html(dom); //add dom into web page
});
The output is an input field asking for the additional passenger name and a select asking for their food requirements
How do I validate these newly created elements? This is what I have so far:
$(document).ready(function(e) {
//validation rule for select
$.validator.addMethod("valueNotEquals", function(value, element, arg){
return arg != value;
}, "Value must not equal arg.");
//validate form
$("#FORMOB7DC24203803DC2").on("click", function(event){
$(this).validate({
rules: {
FullName:{
required: true
},
FullName_0:{
required: true
},
'Number of travelers':{
valueNotEquals: "Please select"
}
}
});
});
});
Is there a way to make this dynamic? Because this form allows for up to 30 passengers and I don't want to manually write in rules FullName_0, FullName_1, FullName_2 etc etc.
I added the rule FullName_0 and it doesn't validate so I don't know what I'm doing wrong.
note - simplified code for readability
You can use attributes to add the rules like
dom += '<input type="text" name="FullName_' + i + '" required>';
Demo: Fiddle
You need to use
$(document).on('click', '#FORMOB7DC24203803DC2', function(e) {
validate();
});
This allows you to validate content added to page at any time.
I am trying to make a select field mandatory on a web page. I know how to do it with help of JS and form attribute 'onsubmit' and returning the function. But the problem is that form code is already written and I dont know how to add attribute now. Let me know if I can append attribute dynamically from JS.
The other way I tried is to call the JS after page loaded. But this isnt making the field mandatory and form can be submitted.
Following is my code..
<!DOCTYPE html>
<html>
<head>
<script>
function f1()
{
var countryValue = document.getElementById('count ID').value;
if (countryValue == "")
{
alert("field value missing");
return false;
}
var stateValue = document.getElementById('state ID').value;
if (stateValue == "")
{
alert("state field value missing");
return false;
}
}
</script>
</head>
<body>
<form method = "post" action = "33.html">
Country: <input type="text" id="count ID">
state: <select id="state ID">
<option></option>
<option value="ap">ap</option>
<option value="bp">bp</option>
</select>
<br>
<input type = "submit">
</form>
<script>window.onload=f1</script>
</body>
</html>
Please help.
Have a look at this since you have messed up the IDs
Live Demo
window.onload=function() {
document.forms[0].onsubmit=function() { // first form on page
var countryValue = this.elements[0].value; // first field in form
if (countryValue == "") {
alert("Please enter a country");
return false;
}
var stateIdx = this.elements[1].selectedIndex; // second field
if (stateIdx < 1) { // your first option does not have a value
alert("Please select a state");
return false;
}
return true; // allow submission
}
}
PS: It is likely that POSTing to an html page will give you an error
To get the last button to do the submission
window.onload=function() {
var form = document.forms[0]; // first form
// last element in form:
form.elements[form.elements.length-1].onclick=function() {
...
...
...
this.form.submit(); // instead of return true
}
}
Once you've got a function to detect improper values (empty mandatory field or anything else, like a bad e-mail address for instance) you have a few different options :
disable the submit button
cancel the onclick event on the button
cancel the submit event on the form
disabling the submit button can be annoying for the user (it might flash on and off while the values are entered).
I had the same issue, but i made a extension. Using hook system to translate fields with "*", in the names, to validate like required field. This is a simple solution not intrusive where is not required addition of fields in the database, only by the use of sufix "*" in configuration of custom fields.
There is the code: https://github.com/voiski/bugzilla-required-field
I'm using a date picker jQuery plugin created by Stefan Petre and available here:
http://www.eyecon.ro/datepicker/#about
This is a code I'm using to apply datepicker to textboxes
$('.tableMstCellECD').DatePicker({
format: 'd/m/Y',
date: $('.tableMstCellECD').val(),
current: $('.tableMstCellECD').val(),
calendars: 3,
onChange: function (formated, dates) {
$('.tableMstCellECD').val(formated);
$('.tableMstCellECD').DatePickerHide();
}
});
It works fine, but obviously updates values of all textboxes instead of selected one. The problem is that there can be different number of texboxes so I cannot hard code access values. I was trying to implement "this" keyword somewhere into this command but did not succeed
I agree with Deepanshu, you should use jQuery UI. If you want to avoid that for some reason, KarelG's solution works just fine, however since you already include jQuery, you can write it like that:
$('.tableMstCellECD').each(function(){
var id = $(this).attr('id');
$(this).DatePicker({
format: 'd/m/Y',
date: $('#' + id).val(),
current: $('#' + id).val(),
calendars: 1,
onChange: function (formated, dates) {
$('#' + id).val(formated);
$('#' + id).DatePickerHide();
}
});
});
You also have to generate unique ID-s for the input elements either on the server or the client side, like this:
<input type="text" id="01" class="tableMstCellECD" />
<input type="text" id="02" class="tableMstCellECD" />
<input type="text" id="03" class="tableMstCellECD" />
<input type="text" id="04" class="tableMstCellECD" />
i also have this problem before. So i wrote an own script (in js) to implement it to textboxes which contains only the class name "datepicker" or something different. To provide support to most browser, i have done it by this way ;
/*
* === javascript file to implement datepicker on form fields for dates
*
* #author : Karel Geiregat
* #version : 1.0.4 - 18 may 2013
*/
// class name which contains input box, chosen for dates
var comparerString = "datepicker";
// get all inputfields, select only those marked with right class name
window.addEventListener('load', function() {
// select all input boxes
var getElements = document.getElementsByTagName("input");
// check count
var count = getElements.length;
// loop through elements
for(var i = 0; i < count; i++) {
// get classname - supported by most major browsers
if (getElements[i].className == comparerString) {
var idField = "#" + getElements[i].id;
$(idField).datepicker({ dateFormat: "yy-mm-dd" });
}
}
});
and in HTML
<input id="form_startDate" class="datepicker" type="text" required="required">
Just write something similar in jQuery. Just add a class name to the textbox which should be tagged with the DatePicker object.
I'm dealing with some legacy HTML/JavaScript. Some of which I have control over, some of which is generated from a place over which I have no control.
There is a dynamically generated form with hidden fields. The form itself is generated via a Velocity template (Percussion Rhythmyx CMS) and JavaScript inserts additional hidden form fields. The end result is hidden form fields generated with the same 'name' attribute. The data is being POSTed to Java/JSP server-side code about which I know very little.
I know that form fields sharing the same 'name' attribute is valid. For some reason the POSTed data is not being recognized the back end. When I examine the POST string, the same-name-keys all contain no data.
If I manipulate the code in my dev environment such that only a single input field exists for a given name, the data IS POSTed to the back end correctly. The problem is not consistent, sometimes, it works just fine.
Is there something I can do to guarantee that the data will be POSTed? Can anyone think of a reason why it would not be?
I should really update my answer and post code here, because POST requests without
variable strings indicates the problem is on the client side.
How about this:
<script type="text/JavaScript">
function disableBlankValues()
{
var elements = document.getElementById("form1").elements;
for (var i = 0; i < elements.length; i++)
{
if (elements[i].value == "")
elements[i].disabled = true;
}
}
</script>
<form action="page.php" method="POST" onsubmit="disableBlankValues()" id="form1">
<input type="hidden" name="field1" value="This is field 1."/>
<input type="hidden" name="field1" value=""/>
</form>
EDIT
I now realize the actual problem (multiple variables with the same name should be passed to JSP as an array) and my solution is probably not what the OP is looking for, but I'm leaving it here just in case it happens to help someone else who stumbles upon this post.
you could use something like:
var form = document.getElementById('yourformid');
var elements = form.getElementsByName('repeatedName');
var count = 0;
for(var item in elements){
elements[item].name += count++;
}
this way you will get each hiddenfield with the names:
name0
name1
name2
...
I've worked out a brute-force solution. Note that I'm pretty aware this is a hack. But I'm stuck in the position of having to work around other code that I have no control over.
Basically, I've created an ONSUBMIT handler which examines the form for the repeated hidden fields and makes sure they are all populated with the correct data. This seems to guarantee that the POST string contains data regardless of how the form gets rendered and the Java back end appears to be happy with it as well.
I've tested this in the following situations:
Code generates single instances of the hidden fields (which does happen sometimes)
Code generates multiple instances of the hidden fields
Code generates no instances of the hidden fields (which should never happen, but hey...)
My 'else' condition contains a tiny bit of MooTools magic, but it's otherwise straight-forward stuff.
Maybe someone else will find this useful one day...
Thanks for the help!
<form method="post" name="loginform" id="loginform" action="/login" onsubmit="buildDeviceFP(this);">
<script type="text/javascript">
function insertFieldValues( fields, sValue )
{
if ( 'length' in fields )
{
// We got a collection of form fields
for ( var x = 0; x < fields.length; x++ ) {
fields[x].value = sValue;
}
}
else
{
// We got a single form field
fields.value = sValue;
}
}
function buildDeviceFP( oForm )
{
// Get the element collections for Device Fingerprint & Language input fields from the form.
var devicePrintElmts = oForm.elements.deviceprint;
var languageElmts = oForm.elements.language;
// 'devicePrintElmts' & 'languageElmts' *should* always exist. But just in case they don't...
if ( devicePrintElmts) {
insertFieldValues( devicePrintElmts, getFingerprint() );
} else if ( oForm.deviceprint ) {
oForm.deviceprint.value = getFingerprint();
} else {
$('logonbox').adopt(
new Element( 'input', {'type':'hidden', 'name':'deviceprint', 'value':getFingerprint()} )
);
}
if ( languageElmts) {
insertFieldValues( languageElmts, getLanguage() );
} else if ( oForm.language ) {
oForm.language.value = getLanguage();
} else {
$('logonbox').adopt(
new Element( 'input', {'type':'hidden', 'name':'language', 'value':getLanguage()} )
);
}
}
</script>