Archaic Form Validation - javascript

I have a form and unfortunately built it without the help of external libraries (which I am now cursing myself for not including). So my form validation isn't just form.validate() or something similar, it's going to have to be an archaic javascript method (time constraints means I cannot implement external libraries because it'd involve rebuilding the form).
All I want is to check all the fields have been filled in - no email validation or post-code validation etc.
I tried a simple version:
if((document.getElementById("fieldA").value != "") || (document.getElementById("fieldB").value != "")){
alert("form okay");
}else{
alert("form not okay");
}
but this doesn't work. The alternative to this would be to nest 45 if statements detecting each field individually but this is tedious and unfeasible.

you can loop trough elements in the form with
document.forms[0].elements
like
var d = document.forms[0].elements
var l = d.length;
for(var i = 0; i < l; i ++) {
var element = d[i];
var type = element.type;
var value = element.value;
var class = element.className;
}
dropdown:
document.forms[0].select.value
radiobuttons:
for (i=0;i<document.forms[0].radios.length;i++) {
if (document.forms[0].radios[i].checked) {
var value = document.forms[0].radios[i].value;
}
}
thanks to external libraries we don't need that to do ourselves these days;)

Your boolean logic is wrong - you want AND (&&) not OR (||) if you want to make all the fields required. As it stands, the validation only checks to see if one field has been filled in.

I think that Caspar's answer is excellent. As an addition to it, what we have on old forms is a function to get elements by class name (not written by us):
function getElementsByClassName(className, tag, elm){
var testClass = new RegExp("(^|\\s)" + className + "(\\s|$)");
var tag = tag || "*";
var elm = elm || document;
var elements = (tag == "*" && elm.all)? elm.all : elm.getElementsByTagName(tag);
var returnElements = [];
var current;
var length = elements.length;
for(var i=0; i<length; i++){
current = elements[i];
if(testClass.test(current.className)){
returnElements.push(current);
}
}
return returnElements;
}
Then we put a class="validate" on each form element that needs validating and have this function run on form submit (where getFormElementValue is a function that handles the various different form elements as in Caspar's answer):
function validate(){
var elementArray = ( getElementsByClassName('validate') ) ;
for ( i=0; i<elementArray.length; i++){
if( getFormElementValue( elementArray[i] ) == '' ){
alert( 'Form not OK' );
return false;
}
}
}
The nice thing about this is that you can easily define which elements are compulsory and which are not without resorting to a list of names/IDs.

Related

How to remove all jQuery validation engine classes from element?

I have a plugin that is cloning an input that may or may not have the jQuery validation engine bound to it.
so, it's classes may contain e.g. validate[required,custom[number],min[0.00],max[99999.99]] or any combination of the jQuery validation engine validators.
The only for sure thing is that the class begins with validate[ and ends with ], but to make it more complicated as in the example above, there can be nested sets of [].
So, my question is, how can I remove these classes (without knowing the full class) using jQuery?
Here is my implementation, It's not using regex, but meh, who said it had too?
//'first validate[ required, custom[number], min[0.00], max[99999.99] ] other another';
var testString = $('#test')[0].className;
function removeValidateClasses(classNames) {
var startPosition = classNames.indexOf("validate["),
openCount = 0,
closeCount = 0,
endPosition = 0;
if (startPosition === -1) {
return;
}
var stringStart = classNames.substring(0, startPosition),
remainingString = classNames.substring(startPosition),
remainingSplit = remainingString.split('');
for (var i = 0; i < remainingString.length; i++) {
endPosition++;
if (remainingString[i] === '[') {
openCount++;
} else if (remainingString[i] === ']') {
closeCount++;
if (openCount === closeCount) {
break;
}
}
}
//concat the strings, without the validation part
//replace any multi-spaces with a single space
//trim any start and end spaces
return (stringStart + remainingString.substring(endPosition))
.replace(/\s\s+/g, ' ')
.replace(/^\s+|\s+$/g, '');
}
$('#test')[0].className = removeValidateClasses(testString);
It might actually be simpler to do that without JQuery. Using the className attribute, you can then get the list of classes using split(), and check whether the class contains "validate[".
var classes = $('#test')[0].className.split(' ');
var newClasses = "";
for(var i = 0; i < classes.length; i++){
if(classes[i].indexOf('validate[') === -1){
newClasses += classes[i];
}
}
$('#test')[0].className = newClasses
I think this solution is even more simple. You just have to replace field_id with the id of that element and if the element has classes like some_class different_class validate[...] it will only remove the class with validate, leaving the others behind.
var that ='#"+field_id+"';
var classes = $(that).attr('class').split(' ');
$.each(classes, function(index, thisClass){
if (thisClass.indexOf('validate') !== -1) {
$(that).removeClass(classes[index])
}
});

Skipping non matching strings when looping through an array in javascript

In the code below I have a form input. When the user searches for a string that happens to be in the array I want it to output the query. When a user happens to search for a string not in the array I want to output an error message. The problem is when a user searches for a string that is other than item [0] in the array (in this case ipsum) they get an error message and then they get their query returned. I want to know if this can be remedied using the code below or if a different methodology for doing this should be pursued ( I know that's an opinion ).
<form>
<input type="text" id="formInput"></input>
<input type = "button" id="search"></input>
</form>
<script>
var search = document.getElementById("search");
var data = ["lorim", "ipsum"];
search.onclick = function(){
var formInput = document.getElementById("formInput").value;
for (i=0; i<data.length; i++){
if (data[i] === formInput) {
alert(data[i]);
}
else{ alert("not working yet"); }
}
};
</script>
you don't need a loop, just use indexOf:
search.onclick = function(){
var formInput = document.getElementById("formInput").value;
if (data.indexOf(formInput) === -1) {
// they entered a bad search term
return;
}
// do the rest of your search logic
};
:) Keep at it.
The thing to remember is that you can only say 'nope didn't find it' after searching everything. So... keep a flag :)
var didntFind = true;
for (var i = 0; i < data.length; i++) {
if (data[i] === formInput) {
alert(data[i]);
didntFind = false;
break;
}
}
if (didntFind) alert('error!');
You can also check if i === data.length-1 after the loop, but the above code should be less confusing for you. Hope this helps

Ways of comparing Text Content between HTML Elements

As the title says, I am looking for a way of comparing the Text content of an HTML Element with another HTML Elements's Text content and only if they are identical, alert a message. Any thoughts? Greatly appreciate it!
(Posted with code): For example, I can't equalize the remItem's content with headElms[u]'s content.
else if (obj.type == 'checkbox' && obj.checked == false) {
var subPal = document.getElementById('submissionPanel');
var remItem = obj.parentNode.parentNode.childNodes[1].textContent;
alert("You have disselected "+remItem);
for (var j=0; j < checkSum.length; j++) {
if (remItem == checkSum[j]) {
alert("System found a match: "+checkSum[j]+" and deleted it!");
checkSum.splice(j,1);
} else {
//alert("There were no matches in the search!");
}
}
alert("Next are...");
alert("This is the checkSum: "+checkSum);
alert("Worked!!!");
var headElms = subPal.getElementsByTagName('h3');
alert("We found "+headElms.length+" elements!");
for (var u=0; u < headElms.length; u++){
alert("YES!!");
if (remItem == headElms[u].textContent) {
alert("System found a matching element "+headElms[u].textContent+" and deleted it!");
}
else {
alert("NO!!");
alert("This didn't work!");
}
}
}
var a = document.getElementById('a');
var b = document.getElementById('b');
var tc_a = a ? a.textContent || a.innerText : NaN;
var tc_b = b ? b.textContent || b.innerText : NaN;
if( tc_a === tc_b )
alert( 'equal' );
Using NaN to ensure a false result if one or both elements don't exist.
If you don't like the verbosity of it, or you need to do this more than once, create a function that hides away most of the work.
function equalText(id1, id2) {
var a = document.getElementById(id1);
var b = document.getElementById(id2);
return (a ? a.textContent || a.innerText : NaN) ===
(b ? b.textContent || b.innerText : NaN);
}
Then invoke it...
if( equalText('a','b') )
alert( 'equal' );
To address your updated question, there isn't enough info to be certain of the result, but here are some potential problems...
obj.parentNode.parentNode.childNodes[1] ...may give different element in different browsers
"System found a matching element ... and deleted it!" ...if you're deleting elements, you need to account for it in your u index because when you remove it from the DOM, it will be removed from the NodeList you're iterating. So you'd need to decrement u when removing an element, or just iterate in reverse.
.textContent isn't supported in older versions of IE
Whitespace will be taken into consideration in the comparison. So if there are different leading and trailing spaces, it won't be considered a match.
If you're a jQuery user....
var a = $('#element1').text(),
b = $('#element2').text();
if (a === b) {
alert('equal!');
}
The triple equals is preferred.
To compare two specific elements the following should work:
<div id="e1">Element 1</div>
<div id="e2">Element 2</div>
$(document).ready(function(){
var $e1 = $('#e1'),
$e2 = $('#e2'),
e1text = $e1.text(),
e2text = $e2.text();
if(e1text == e2text) {
alert("The same!!!");
}
});
I will highly recommend using jQuery for this kind of comparison. jQuery is a javascript library that allows you to draw values from between HTML elements.
var x = $('tag1').text();
var y = $('tag2').text();
continue js here
if(x===y){
//do something
}
for a quick intro to jQuery...
First, download the file from jQuery.com and save it into a js file in your js folder.
Then link to the file. I do it this way:
Of course, I assume that you're not doing inline js scripting...it is always recommended too.
A simple getText function is:
var getText = (function() {
var div = document.createElement('div');
if (typeof div.textContent == 'string') {
return function(el) {
return el.textContent;
}
} else if (typeof div.innerText == 'string') {
return function(el) {
return el.innerText;
}
}
}());
To compare the content of two elements:
if (getText(a) == getText(b)) {
// the content is the same
}

Check and control the number of checked check boxes with JavaScript

I am validating some check boxes and would like for the user to be able to select only 4 (from 7 possible) and disable the others if the current box is being checked(if there are already 3 checked) or enable the everything if the current box is being unchecked. I'm really not sure where's the problem. This is my first experience with JavaScript...
function verify_selected(selected_check_box_id) {
var count = 0;
var selected_check_boxes = new Array();
var check_boxes = new Array();
var inputs = document.getElementsByTagName("input");
for( var i in inputs ) {
if( inputs[i].type == "checkbox" ) check_boxes.push( inputs[i] );
}
// get current checkbox
for( var i in check_boxes ) if( check_boxes[i].id == selected_check_box_id ) var current_check_box = check_boxes[i];
var current_check_box_is_checked = current_check_box.checked;
// get all "checked"
for( var i in check_boxes ) {
if( check_boxes[i].checked ) {
selected_check_boxes.push( check_boxes[i] );
count += 1;
}
}
if( current_check_box_is_checked ) {
// checking
if( count < 4 ) {
current_check_box.checked = true;
// count = 4 - disabling
if( count == 4 ) {
for( var i in check_boxes ) {
if( !check_boxes[i].checked ) check_boxes[i].disabled = true;
}
}
}
else current_check_box.checked = false;
} else {
// unchecking
// count is < 4 -> enabling
for( var i in check_boxes ) {
check_boxes[i].disabled = false;
}
}
}
Any help is welcome,
thanks in advance.
There were a couple of things wrong. Lets give the good version first.
I also put up a demo at: http://jsbin.com/ajimi
function verify_selected(currentCheckbox) {
var count = 0;
var selected_check_boxes = []; // this will be fine...
var check_boxes [];
var inputs = document.getElementsByTagName("input");
for( var i in inputs ) {
if( inputs[i].type == "checkbox" ) check_boxes.push( inputs[i] );
}
// get all "checked"
for( var i in check_boxes ) {
if( check_boxes[i].checked ) {
count += 1;
}
}
if( currentCheckbox.checked && (count == 4)) {
for( var i in check_boxes )
if( !check_boxes[i].checked )
check_boxes[i].disabled = true;
} else {
for( var i in check_boxes )
check_boxes[i].disabled = false;
}
}
In the original version, you've got a piece of code which looked like:
if (count < 4) {
if (count == 4) {
Not gonna happen. So, that was corrected.
As you saw also in another answer, we changed the function to take out looking for an ID. Rather than figuring out the ID in some separate function (I assume you're tracking the "last clicked" by some other function which occurs), just use the this modifier to pass it into the function.
Alright, last but not least, what this would look like in jQuery. Hopefully this will help a little as to understanding how it works and why it's worth using:
(see example: http://jsbin.com/ihone)
function limitSelected(e) {
// get all of your checkboxes
var checkBoxes = $(e.currentTarget).parent().children().filter('input:checkbox');
// get the number of checkboxes checked, if 4, we'll disable
var disableCheckBoxes = (checkBoxes.filter(':checked').length == 4);
// enable checkboxes if we have < 4, disable if 4
checkBoxes.filter(':not(:checked)').each(function() {
this.disabled = disableCheckBoxes;
});
}
// when the document is ready, setup checkboxes to limit selection count
// if you have a particular div in which these checkboxes reside, you should
// change the selector ("input:checkbox"), to ("#yourDiv input:checkbox")
$(function() {
$('input:checkbox').click(limitSelected);
});
The other thing I will note about this version is that it works on the group of checkboxes within a div, as opposed to your version which will pick up checkboxes on the entire page. (which is limiting.
From a brief skim, your code seems much too complex for the task.
Can I suggest using something like jquery? You can quite easily select the relevant check boxes using the psudeo-selector ':checked'. Also, have a look at this check box tutorial.
If you don't want to use a library, I'd suggest first creating a function that can count the number of checked check boxes. Then create a function that can disable or enable all unchecked check boxes. Finally, combine the two, and register a function to trigger on the click event for the check boxes.
As cofiem said, your code looks rather complex for what you want to achieve; I recommend breaking it down into a few, smaller functions, to re-use code and make less complex.
First, implement a function to get all of the checkboxes on the page:
function getCheckboxes()
{
var inputs = document.getElementsByTagName("input");
var checkboxes = new Array();
for(var i=0;i<inputs.length;++i) {
if(inputs[i].type=="checkbox")
checkboxes.push(inputs[i]);
}
return checkboxes;
}
Then a function to enable/disable the checkboxes:
function setDisabled(state) {
var checkboxes = getCheckboxes();
for(i=0;i<checkboxes.length;++i) {
//Only unchecked checkboxes will need to be enabled/disabled
if(!checkboxes[i].checked)
checkboxes[i].disabled = state;
}
}
Now implement your function to verify whether the checkboxes need to be enabled or disabled:
function verify_selected(checkbox) {
var checkboxes = getCheckboxes();
var count=0;
for(i=0;i<checkboxes.length;++i) {
if(checkboxes[i].checked)
count++;
}
if(count>=4)
setDisabled(true);
else
setDisabled(false);
}
I have changed your function declaration to pass the actual checkbox object rather than an identifier string; this is much easier to call the function:
<input type="checkbox" onClick="verify_selected(this);">
//Insert 7 of these..
As you can see the code is much easier to read and maintain, and it is much less complex.

Fetch the data of a particular <td> in a table

I need to get the data of an particular <td>, but I don't have any id or name for that particular <td>. How do you get the contents of that <td>?
For example:
<table>
<tr><td>name</td><td>praveen</td></tr>
<tr><td>designation</td><td>software engineer</td></tr>
</table>
Is it possible to get the value "designation" from this table.. I need to extract the word "software engineer" using javascript.
I prefer to use jQuery to do all the heavy lifting for this sort of task.
For example, the following function will return the text of the next element of the same type that you're searching for:
function GetNextChildText(tagToFind, valueToFind) {
var nextText = "";
$(tagToFind).each(function(i) {
if ($(this).text() == valueToFind) {
if ($(this).next() != null && $(this).next() != undefined) {
nextText = $(this).next().text();
}
}
});
return (nextText);
}
So, for your example table, your call to return the designation could be:
var designationText = GetNextChildText('td', 'designation');
And the result is that the variable designationText would contain the value 'software engineer'.
A quick solution:
function GetTdContent(label)
{
var TDs = document.getElementsByTagName("TD");
var foundFlag = false;
for (i = 0; i < TDs.length; i++)
{
if (foundFlag) return TDs[i].innerHTML;
foundFlag = TDs[i].innerHTML.toLower() == label.toLower();
}
}
elsewhere call:
var value = GetTdContent("designation");
Explanation:
The function iterates all TDs in the document. If it finds one with the given label, say "designation", it loops one more time and returns the next TD content.
This makes a few assumptions about your source HTML. If you know your data though, it can be enough.
Something along the line of:
(not tested, just quick code to give an idea)
var tables = document.getElementById('TABLE'); // instead of document.all.tag
var rows;
var cells;
var maxCells = 1;
var designation;
if (tables) {
for (var t=0; t<tables.length; t++) {
rows = tables[t].all.tags('TR');
if (tables[t].all.tags('TABLE').length == 0) {
for (var r=0; r<rows.length; r++) {
if (rows[r].innerText != '') {
cells = rows[r].all.tags('TD');
for (var c=0; c<cells.length; c++) {
if (cells[c].innerText == 'designation' && c<(cells.length-1)) {
designation = cells[c+1].innerText;
}
}
}
}
}
}
}
Since document.all is IE specific, you should rather user getElementById, with the following to redefine that function for IE:
if (/msie/i.test (navigator.userAgent)) //only override IE
{
document.nativeGetElementById = document.getElementById;
document.getElementById = function(id)
{
var elem = document.nativeGetElementById(id);
if(elem)
{
//make sure that it is a valid match on id
if(elem.attributes['id'].value == id)
{
return elem;
}
else
{
//otherwise find the correct element
for(var i=1;i<document.all[id].length;i++)
{
if(document.all[id][i].attributes['id'].value == id)
{
return document.all[id][i];
}
}
}
}
return null;
};
}
Use XPath (tutorial here, including instructions for IE and other browsers: http://www.w3schools.com/XPath/xpath_examples.asp)
The xpath for your example is
//table/tr/td[text()="designation"]/following::td
("the td that follows the td with text "designation" that's in a tr that's in a table somewhere in the document")
Simpler Xpaths are possible - if it's the only table cell that could contain 'designation' you could use
//td[text()="designation"]/following::td
One issue with writing code to do the particular search is that it needs changing, possibly significantly, if the structure of your page changes. The Xpath may not need to change at all, and if it does, it's only one line.
Tomalak's a little quicker:
<script type="text/javascript">
function getText(tText){
var tds = document.getElementsByTagName("td");
for(var i=0, im=tds.length; im>i; i++){
if(tds[i].firstChild.nodeValue == tText)
return tds[i].nextSibling.firstChild.nodeValue;
}
}
</script>

Categories

Resources