PDA

View Full Version : get form elements by tag name



Oziam
01-19-2011, 10:16 PM
Hi all,
I have a small function that will search a page for elements that contain a certain class name, if found the class name is changed!
This works great but I feel it is inefficient due to the fact that it searches all tags in the entire page, not a problem with a small file but if you have a large file I feel this would be a strain on resources....or is this not really an issue.


What I need is a way to search just for a specific list of form elements,

e.g var list = 'input, select, textarea' etc...

The function I am using now is below;

resetClass = function(){
var elms = document.getElementsByTagName("*");
var len = elms.length;
for (var i = 0; i < len; i++){
thisElm = elms[i];
if (thisElm.className == 'red'){
document.forms[formid][thisElm.name].className = 'blue';
}
}
return;
}

Thanks!!!

Oziam
01-20-2011, 03:09 AM
Well I figured out a solution that works, but once again
I don't really know which method would be more efficient?

Method 1: Searches ALL document tags for a match

resetClass = function(){
var elms = document.getElementsByTagName("*");
var len = elms.length;
for (var i = 0; i < len; i++){
thisElm = elms[i];
if (thisElm.className == 'red'){
document.forms[formid][thisElm.name].className = 'blue';
}
}
return;
}
Method 2: Searches ONLY tags defined in array

resetClass = function(){
var x;
var elms = new Array("input","select","textarea");

for (x in elms){
var et = document.getElementsByTagName(elms[x]);
var len = et.length;
for (var i = 0; i < len; i++){
thisEt = et[i];
if (thisEt.className == 'red'){
document.forms[form_id][thisEt.name].className = 'blue';
}
}
}
return;
}

Even though the code works OK I want to use the most efficient,
I have only been writing JS for a couple of weeks and am slowly getting a grasp on it but I don't really understand about resource usage etc...

Thanks!!!

jscheuer1
01-20-2011, 05:42 AM
Since you're going to the form eventually anyway, why not use it to get its element collection? That's probably the most efficient:


function resetClass(){
var form = document.getElementById('form_id'), els = form.elements, i = els.length - 1;
for (i; i > -1; --i){
if(els[i].className === 'red'){
els[i].className = 'blue';
}
}
}

To really test efficiency though, you need a time trial, like:


function resetClass(){
var t = new Date().getTime();
var form = document.getElementById('form_id'), els = form.elements, i = els.length - 1;
for (i; i > -1; --i){
if(els[i].className === 'red'){
els[i].className = 'blue';
}
}
alert(new Date().getTime() - t);
}

Oziam
01-20-2011, 07:47 AM
Ahh of course, that makes more sense, I didn't think of using form.elements,
yeah I think that would be a better solution.
I wasn't sure how to do a time trial in JS,


In PHP I use;


<?PHP
$start_time = microtime(true);

// do something

$end_time = microtime(true);

echo "Generated in " . round(($end_time - $start_time),3) . " seconds";
?>

Thanks again John! :D

Oziam
01-20-2011, 08:12 AM
Hmmm,

Time trial always returns 0 with all 3 methods,
must be too quick on local server.

jscheuer1
01-20-2011, 10:23 AM
I was going to mention that. Most CPU's can handle that in 'nothing flat', in under a millisecond. And javascript doesn't do microtime. So you would have to do a bunch of them - say 100 or even 1000, to get a better idea:

time_trial_0.htm -

<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>
<body>
<form id="form_id" action="">
</form>
<script type="text/javascript">
function resetClass(){
var t = new Date().getTime();
var form = document.getElementById('form_id'), els = form.elements, i = els.length - 1;
for (i; i > -1; --i){
if(els[i].className === 'red'){
els[i].className = 'blue';
}
}
alert(new Date().getTime() - t);
}
var form = document.getElementById('form_id'), els = ['input', 'select', 'textarea'], colors = ['red', 'blue'], f = 0, el;
while (f < 1000){
el = document.createElement(els[f % 3]);
el.className = colors[++f % 2];
form.appendChild(el);
}
resetClass();
</script>
</body>
</html>

You could do similar with the other methods - say a time_trial_1.htm, and a time_trial_2.htm.

Just a mild warning though. The above code has been tested and works. But once you edit it, you might create an endless loop situation where you have to use Task Manager (or equivalent) to end the browser's process. Just make sure that only one instance of that browser is open and that only one tab of that browser is open. That way if it does crash, you won't lose other open sites and/or have to recover them next time you launch the browser.

For the above code I got:


Firefox: 101
IE: 30
Chrome: 5


Versions 3, 9, and 8 respectively. So even the fastest - Chrome, showed enough elapsed time to make comparison possible.

I later did this for the other two versions. They were about the same as each other, with the second one (array of tag names to check) taking perhaps a hair longer. They came in at:


Firefox: 109
IE: 44
Chrome: 400


If you do multiple tests, you would get different results, these are approximate averages.

The other test pages:

time_trial_1.htm -

<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>
<body>
<form id="form_id" name="form_id" action="">
</form>
<script type="text/javascript">
function resetClass(){
var t = new Date().getTime();
var elms = document.getElementsByTagName("*");
var len = elms.length;
for (var i = 0; i < len; i++){
thisElm = elms[i];
if (thisElm.className == 'red'){
document.forms['form_id'][thisElm.name].className = 'blue';
}
}
alert(new Date().getTime() - t);
}
var form = document.getElementById('form_id'), els = ['input', 'select', 'textarea'], colors = ['red', 'blue'], f = 0, el;
while (f < 1000){
el = document.createElement(els[f % 3]);
el.className = colors[++f % 2];
el.name = 'name_' + f;
form.appendChild(el);
}
resetClass();
</script>
</body>
</html>

time_trial_2.htm -

<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>
<body>
<form id="form_id" name="form_id" action="">
</form>
<script type="text/javascript">
function resetClass(){
var t = new Date().getTime();
var x;
var elms = new Array("input","select","textarea");

for (x in elms){
var et = document.getElementsByTagName(elms[x]);
var len = et.length;
for (var i = 0; i < len; i++){
thisEt = et[i];
if (thisEt.className == 'red'){
document.forms['form_id'][thisEt.name].className = 'blue';
}
}
}
alert(new Date().getTime() - t);
}
var form = document.getElementById('form_id'), els = ['input', 'select', 'textarea'], colors = ['red', 'blue'], f = 0, el;
while (f < 1000){
el = document.createElement(els[f % 3]);
el.className = colors[++f % 2];
el.name = 'name_' + f;
form.appendChild(el);
}
resetClass();
</script>
</body>
</html>

Oziam
01-20-2011, 09:11 PM
W:eek:W

Ok that gives me alot to play with, it seems that either method
is not really an issue on CPU resources.

Cheers!

jscheuer1
01-21-2011, 04:52 AM
I thought that Chrome was rather dramatic and that IE was significant. I was disappointed in Firefox because I had thought it was better at things like that.

All browsers were faster with the method I proposed. They might be faster still though using form.getElementsByTagName('*') - which is generally thought to be more efficient, and 'my' way of looping things (already proven by others in time trials to be more efficient than the usual way).

It was:

time_trial_3.htm -

<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>
<body>
<form id="form_id" action="">
</form>
<script type="text/javascript">
function resetClass(){
var t = new Date().getTime();
var els = document.getElementById('form_id').getElementsByTagName('*'), i = els.length - 1;
for (i; i > -1; --i){
if(els[i].className === 'red'){
els[i].className = 'blue';
}
}
alert(new Date().getTime() - t);
}
var form = document.getElementById('form_id'), els = ['input', 'select', 'textarea'], colors = ['red', 'blue'], f = 0, el;
while (f < 1000){
el = document.createElement(els[f % 3]);
el.className = colors[++f % 2];
form.appendChild(el);
}
resetClass();
</script>
</body>
</html>


Firefox: 101
IE: 13
Chrome: 2


Now you might say it doesn't matter. But you never know when you may need to process more nodes than you first thought or need to do these sorts of things a lot in one pass of some more complex code. At that point it can become significant. I've seen real life cases where it is. And I have a fairly up to date computer. If your audience includes those with older equipment, the differences are probably much more significant.

As a side note, my method for generating the nodes could be much more efficient. But as we aren't measuring that, I didn't bother tightening it up.

Oziam
01-22-2011, 12:12 AM
My scores are below; for averages taken of methods 1-3;

Method 1:
========
IE 8: 105
Opera 11: 4
FF 3.6: 85
Safari 5: 168

Method 2:
========
IE 8: 102
Opera 11: 3
FF 3.6: 85
Safari 5: 170

Method 3:
========
IE 8: 15
Opera 11: 2
FF 3.6: 78
Safari 5: 1

Well looking at the results method 3 is definatley the fastest way for all
browsers but look at the difference for Safari, that is not a typo, 1 was the
average of 20 passes, actually most resulted in 0 but I thought I would put 1 to be fair!!
Another interesting result was IE 8, method 3 was substantially faster?
I haven't tried IE 9(deleted it after touble with 64bit version) and Chrome I don't have!