Results 1 to 9 of 9

Thread: get form elements by tag name

  1. #1
    Join Date
    Jan 2011
    Location
    QLD, Australia
    Posts
    23
    Thanks
    3
    Thanked 1 Time in 1 Post

    Default get form elements by tag name

    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;
    Code:
    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!!!

  2. #2
    Join Date
    Jan 2011
    Location
    QLD, Australia
    Posts
    23
    Thanks
    3
    Thanked 1 Time in 1 Post

    Default

    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
    Code:
    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
    Code:
    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!!!

  3. #3
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    29,000
    Thanks
    44
    Thanked 3,198 Times in 3,160 Posts
    Blog Entries
    12

    Default

    Since you're going to the form eventually anyway, why not use it to get its element collection? That's probably the most efficient:

    Code:
    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:

    Code:
    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);
    }
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  4. #4
    Join Date
    Jan 2011
    Location
    QLD, Australia
    Posts
    23
    Thanks
    3
    Thanked 1 Time in 1 Post

    Default

    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 Code:
    <?PHP
    $start_time 
    microtime(true);

    // do something

    $end_time microtime(true);

    echo 
    "Generated in " round(($end_time $start_time),3) . " seconds";
    ?>
    Thanks again John!

  5. #5
    Join Date
    Jan 2011
    Location
    QLD, Australia
    Posts
    23
    Thanks
    3
    Thanked 1 Time in 1 Post

    Default

    Hmmm,

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

  6. #6
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    29,000
    Thanks
    44
    Thanked 3,198 Times in 3,160 Posts
    Blog Entries
    12

    Default

    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 -
    Code:
    <!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 -
    Code:
    <!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 -
    Code:
    <!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>
    Last edited by jscheuer1; 01-20-2011 at 02:00 PM. Reason: did more tests
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  7. The Following User Says Thank You to jscheuer1 For This Useful Post:

    Oziam (01-20-2011)

  8. #7
    Join Date
    Jan 2011
    Location
    QLD, Australia
    Posts
    23
    Thanks
    3
    Thanked 1 Time in 1 Post

    Default

    WW

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

    Cheers!

  9. #8
    Join Date
    Mar 2005
    Location
    SE PA USA
    Posts
    29,000
    Thanks
    44
    Thanked 3,198 Times in 3,160 Posts
    Blog Entries
    12

    Default

    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 -
    Code:
    <!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.
    - John
    ________________________

    Show Additional Thanks: International Rescue Committee - Donate or: The Ocean Conservancy - Donate or: PayPal - Donate

  10. #9
    Join Date
    Jan 2011
    Location
    QLD, Australia
    Posts
    23
    Thanks
    3
    Thanked 1 Time in 1 Post

    Thumbs up

    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!
    Last edited by Oziam; 01-22-2011 at 04:49 AM.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •