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.
Related
I was wondering if anyone can help? What I am trying to do is retrieve the word count from javascript code into a form and then pass it into php along with the rest of the form which will check that the word count is a certain length or else it won't be submitted.
The javascript is as follows.
counter = function() {
var value = $('#msg').val();
if (value.length == 0) {
$('#wordCount').html(0);
$('#totalChars').html(0);
$('#charCount').html(0);
$('#charCountNoSpace').html(0);
return;
}
var regex = /\s+/gi;
var wordCount = value.trim().replace(regex, ' ').split(' ').length;
var totalChars = value.length;
var charCount = value.trim().length;
var charCountNoSpace = value.replace(regex, '').length;
$('#wordCount').html(wordCount);
$('#totalChars').html(totalChars);
$('#charCount').html(charCount);
$('#charCountNoSpace').html(charCountNoSpace);
};
$(document).ready(function() {
$('#count').click(counter);
$('#msg').change(counter);
$('#msg').keydown(counter);
$('#msg').keypress(counter);
$('#msg').keyup(counter);
$('#msg').blur(counter);
$('#msg').focus(counter);
});
My problem is returning wordCount into a hidden field in a form. I am not too good with javascript and am not sure how to modify this code to make it work. The rest I can figure out but am stuck here. Thank you for your help, it is greatly appreciated.
$('#wordCount').val(wordCount);
$('#totalChars').val(totalChars);
$('#charCount').val(charCount);
$('#charCountNoSpace').val(charCountNoSpace);
Use .val() instead of .html(), because .val() refers to the value of an input field.
Your HTML inside the form should include a hidden input field:
<input type="hidden" id="word_count" name="word_count" value="0" />
Then inside your JS:
$('#word_count').val(wordCount);
All together embedded inside your function:
counter = function() {
var value = $('#msg').val();
if (value.length == 0) {
$('#wordCount').html(0);
$('#totalChars').html(0);
$('#charCount').html(0);
$('#charCountNoSpace').html(0);
return;
}
var regex = /\s+/gi;
var wordCount = value.trim().replace(regex, ' ').split(' ').length;
var totalChars = value.length;
var charCount = value.trim().length;
var charCountNoSpace = value.replace(regex, '').length;
$('#wordCount').html(wordCount);
$('#word_count').val(wordCount);
$('#totalChars').html(totalChars);
$('#charCount').html(charCount);
$('#charCountNoSpace').html(charCountNoSpace);
};
$(document).ready(function() {
$('#count').click(counter);
$('#msg').change(counter);
$('#msg').keydown(counter);
$('#msg').keypress(counter);
$('#msg').keyup(counter);
$('#msg').blur(counter);
$('#msg').focus(counter);
});
If you have INPUT fields in your form, use val()
$('#wordCount').val(wordCount)
That would work for a field like this:
Be aware that there's a difference between "id" and "class". jQuery allows you to select elements based on their properties. The "id" property gets selected with "#", just like you'd do it in CSS. So make sure you have that "id='wordCount'" defined in your hidden field.
Have a look at this http://www.hscripts.com/scripts/JavaScript/word-count.php
There are plenty of examples online, just google "javascript count words in textbox"
Some imporntant notes:
A very long string with no spaces is still 1 word so don't forget to set the max length for fields
If you are doing this as a sort of validation be aware of the fact that you can not trust a form field because it can be easily manipulated, so don't forget to check the word count on the server side after the form is submitted.
The Code that you are showing is not just javascript it also includes jquery, please make sure you included jquery
<script src = "http://code.jquery.com/jquery-1.11.1.min.js"></script>
$('#field').val('asdf'); //Sets Value of a input type="text"
$('#field').html('sadf'); //Sets the html of a div
Using javascript you use either value for a input or innerHtml for a div or other text based element
document.getElementById('field').value = 'asdfsadf';
document.getElementById('field').innerHtml= 'asdfsadf';
Also instead of using a form submit consider using jquery $.ajax(there is nothing wrong with form submits but there are benefits to knowing jquery as well such as you came make async requests
http://api.jquery.com/jquery.ajax/
You will want to use a hidden field such as the following and have it in the form
<form id="myform" action='posttome.php'>
<input type="hidden" id="wordCount"/>
<input type="submit" value="sbumit"> //Submits Form
</form>
Then set its value by using of of three methods, a an elements html, an elements value, or a javascript variable $('#wordCount').val()
$('#wordCount').val($('#wordCountSoruceDiv').html()); // Sets the value to another divs html
$('#wordCount').val($('#wordCountSourceInput').val()); // Sets the value to another inputs value
$('#wordCount').val(wordCountVariable); // Sets the value to a variable
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!
I'm working with Zend Framework 1.12 and I've need to be able to dynamically add and delete fields from a sub-form, in this case we're associating hyperlinks to a parent "promotion".
I haven't found a way to accomplish dynamically adding and removing elements via Zend, and the rare tutorial I've found that claimed to do this are half a decade old and aren't working when I attempt them.
So what I am doing is storing the links I need to work with in a Zend Hidden input field and then dealing with the JSON data after I submit. Not very efficient, but it's the only thing I've gotten to work so far.
Below is the section of the code I'm working with:
Assume a form like:
<form action="/promos/edit/promo_id/15" method="POST" id="form_edit">
<!-- input is Zend_Form_Element_Hidden -->
<input type="hidden" id="link_array" value="{ contains the JSON string }"/>
<button id="add_link">Add Link</button>
</form>
The purpose is that every time the Add Link button is pressed, the form adds fields to allow the user to input new hyperlinks that will be associated with the specific items.
Here's the function:
// add links
$('#add_link').click(
function(e) {
e.preventDefault();
link = '<div class="p_link new_link">' +
'<div class="element_wrap">' +
'<label for="link_name" class="form_label optional">Text: </label>' +
'<input type="text" id="new_link_name" name="link_name"/>' +
'</div>' +
'<div class="element_wrap">' +
'<label for="link_http" class="form_label optional">http://</label>' +
'<input type="text" id="new_link_http" name="link_http"/>' +
'</div>' +
'<div class="element_wrap">' +
'<button class="submit delete_link">Delete</button>' +
'</div>' +
'</div>';
$('#add_link').prev().after(link);
}
);
Now, what I need to do is on submit, for every new_link class element, to take the links name and http reference and place it in a json object. Here's the code as I have it so far (I know I don't have both input fields represented at this point):
$('#submit').click(
function(e) {
e.preventDefault();
var link_array = [];
var new_links = document.getElementsByClassName('new_link');
$.each(new_links, function() {
console.log(this);
var n = $(this).children('#new_link_name').text();
console.log(n);
link_array.push({'link_name':n}); //'link_http':h
});
console.log(JSON.stringify(link_array));
}
);
My problem is that: var new_links = document.getElementsByClassName('new_link'); will collect all the newly added new_link elements, but it does not pull in any value that has been input into the text fields.
I need to know how I can apparently bind any input I make to the input field's value attribute, because right now anything I type into these new elements are tossed out and the field appears empty when it's anything but.
$('#submit').click(
function(e) {
e.preventDefault();
var link_array = [];
var new_links = $('.new_link');
$.each(new_links, function() {
console.log(this);
var n = $(this).find('input').val(); // you need input values! This line //is changed...
console.log(n);
link_array.push({'link_name':n}); //'link_http':h
});
console.log(JSON.stringify(link_array));
}
);
JSFIDDLE: http://jsfiddle.net/DZuLJ/
EDit: You can't have multiple IDS (make class for each input, and target class, if you want link names and http's)
I created a div and a button. when the button clicked, there will be a group of element(included 1 select box and 2 text inputs) inserted into the div. User can add as many group as they can, when they finished type in data of all the group they added, he can hit save button, which will take the value from each group one by one into the JSON object array. But I am stuck in the part how to get the value from each group, so please help, thank you.
The code for the div and the add group button function -- AddExtra() are listed below:
<div id="roomextra">
</div>
function AddExtra() {
$('#roomextra').append('<div class=extra>' +
'<select id="isInset">' +
'<option value="Inset">Inset</option>' +
'<option value="Offset">OffSet</option>' +
'</select>' +
'Length(m): <input type="text" id="insetLength">' +
'Width(m): <input type="text" id="insetWidth">' +
'Height(m): <input type="text" id="insetHeight">' +
'</div>');
}
function GetInsetOffSetArray (callBack) {
var roomIFSDetail = [{
"IsInset": '' ,
"Length": '' ,
"Width": '' ,
"Height": ''
}];
//should get all the value from each group element and write into the array.
callBack(roomIFSDetail);
}
This should just about do it. However, if you're dynamically creating these groups, you'll need to use something other than id. You may want to add a class to them or a data-* attribute. I used a class, in this case. Add those classes to your controls so we know which is which.
var roomIFSDetail = [];
var obj;
// grab all of the divs (groups) and look for my controls in them
$(.extra).each(function(){
// create object out of select and inputs values
// the 'this' in the selector is the context. It basically says to use the object
// from the .each loop to search in.
obj = {
IsInset: $('.isInset', this).find(':selected').val() ,
Length: $('.insetLength', this).val() ,
Width: $('.insetWidth', this).val() ,
Height: $('.insetHeight', this).val()
};
// add object to array of objects
roomIFSDetail.push(obj);
});
you'd better not to use id attribute to identity the select and input, name attribute instead. for example
$('#roomextra').append('<div class=extra>' +
'<select name="isInset">' +
'<option value="Inset">Inset</option>' +
'<option value="Offset">OffSet</option>' +
'</select>' +
'Length(m): <input type="text" name="insetLength">' +
'Width(m): <input type="text" name="insetWidth">' +
'Height(m): <input type="text" name="insetHeight">' +
'</div>');
}
and then, usr foreach to iterate
$(".extra").each(function() {
var $this = $(this);
var isInset = $this.find("select[name='isInset']").val();
var insetLength = $this.find("input[name='insetLength']").val();
// ... and go on
});
A common problem. A couple things:
You can't use IDs in the section you're going to be repeating, because IDs in the DOM are supposed to be unique.
I prefer to use markup where I'm writing a lot of it, and modify it in code rather than generate it there.
http://jsfiddle.net/b9chris/PZ8sf/
HTML:
<div id=form>
... non-repeating elements go here...
<div id=roomextra>
<div class=extra>
<select name=isInset>
<option>Inset</option>
<option>OffSet</option>
</select>
Length(m): <input id=insetLength>
Width(m): <input id=insetWidth>
Height(m): <input id=insetHeight>
</div>
</div>
</div>
JS:
(function() {
// Get the template
var container = $('#roomextra');
var T = $('div.extra', container);
$('#addGroup').click(function() {
container.append(T.clone());
});
$('#submit').click(function() {
var d = {};
// Fill d with data from the rest of the form
d.groups = $.map($('div.extra', container), function(tag) {
var g = {};
$.each(['isInset', 'insetLength', 'insetWidth', 'insetHeight'], function(i, name) {
g[name] = $('[name=' + name + ']', tag).val();
});
return g;
});
// Inspect the data to ensure it's what you wanted
debugger;
});
})();
So the template that keeps repeating is written in plain old HTML rather than a bunch of JS strings appended to each other. Using name attributes instead of ids keeps with the way these elements typically work without violating any DOM constraints.
You might notice I didn't quote my attributes, took the value attributes out of the options, and took the type attributes out of the inputs, to keep the code a bit DRYer. HTML5 specs don't require quoting your attributes, the option tag's value is whatever the text is if you don't specify a value attribute explicitly, and input tags default to type=text if none is specified, all of which adds up to a quicker read and slimmer HTML.
Use $(".extra").each(function() {
//Pull info out of ctrls here
});
That will iterate through all of your extra divs and allow you to add all values to an array.
Aim is to detect if after page load input values are changed.
Input fields (19 fields) for example
<input type="text" name="date_day1" id="date_day1" value=" >
<input type="text" name="date_month1" id="date_month1" value=" >
<input type="text" name="date_year1" id="date_year1" value=" >
<input type="text" name="amount1" id="amount1" value=" >
Then hidden input field like this
<input type="text" name="is_row_changed1" id="is_row_changed1" value="">
<script>
$("#date_day1").on("change", function () {
document.getElementById('is_row_changed1').value = 1;
});
$("#date_month1").on("change", function () {
document.getElementById('is_row_changed1').value = 1;
});
</script>
If in any of input fields (19 fields) value is changed, then I need to reflect it in this hidden input field (I decided to set the hidden input field value to 1).
After that ajax with php where I check if the hidden input field value is 1. If 1, then update mysql. Aim is to reduce usage of server resources.
Question
Javascript code for the hidden input field would be long. May be some way (code) to make is shorter (simplier)?
Add a row_changed class to each input then you can target them all with one call:
$(".row_changed").on("change", function () {
document.getElementById('is_row_changed1').value = 1;
});
(you can also simplify it even more with QuickSilver's comment.)
You could use JQuery selectors in order to set the same "input changed" callback for all input elements declared in your HTML code:
var anyFieldChanged = false; //Global variable
function changedCallBack()
{
anyFieldChanged = true;
alert('Fields changed');
}
allInputs = $('input');
allInputs.each(function() { this.onchange = yourCallBack(); });
I don't know if it's just in your example code, but you have several elements with the same ID, which is not valid. Each ID should be unique (which is the purpose of any ID). You can either add a class to each input you want to track and select on that like Shawn said or if you want to track every input except the hidden on the page you can use
$("input:[type!=hidden]").on("change", function () {
document.getElementById('is_row_changed1').value = 1;
});
Use like this.
<script>
$("#date_day1").on("change", function () {
$('#is_row_changed1').val(1);
});
$("#date_month1").on("change", function () {
$('#is_row_changed1').val(1);
});
// etc
</script>