SitePoint Sponsor

User Tag List

Results 1 to 16 of 16
  1. #1
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    blahblahblah
    Posts
    1,447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    easy with jQuery. How hard with straight Javascript?

    Hi,

    I'm getting accustomed to using jQuery, without really knowing Javascript.

    But this is it. I want to learn Javascript. I've read a few interesting articles about the language foundations, but I've lost hours trying to do simple things.

    I was wondering how hard it would be to translate this jQuery snippet to plain Javascript. I would for sure make tremendous progress if I can get a look at a clear and consise approach to such common problems.

    Code:
     $(document).ready(function() {
     
     
       $(".test").hover(function() {
         $(this).addClass("green");
       },function(){
         $(this).removeClass("green");
       });
    
       $(".test").click(function() {
         $(this).toggleClass("red");
       });
       
       
     });
    HTML Code:
    <div class="test">
    </div>
    Regards

    -jj.

  2. #2
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Depends.

    jQuery will properly work even if these elements have multiple classnames or event handlers already. If your test div would only have a single class name, and only a single event handler each for onmouseover, onmouseout, onclick, then writing similar functionality would be about 20 lines of code or so. However, if you want it to work properly when your element may have multiple classes or event handlers for the same event, im guessing prob 50-60 lines of code.

    I'm also making the assumption you would be ok with using window.onload instead of jQuery's ready() function. If not, more code needed.

  3. #3
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    blahblahblah
    Posts
    1,447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So I would start with this:

    Code:
    window.onload = function(){ 
    //do stuff here
    }
    I tried to find how you can find an element by class, but I couldn't. How would I catch all the elements with the "test" class?


  4. #4
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2008
    Posts
    5,757
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    google for getelementsbyclassname

  5. #5
    Function Curry'er JimmyP's Avatar
    Join Date
    Aug 2007
    Location
    Brighton, UK
    Posts
    2,006
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Code JavaScript:
    function getElementsByClass(c) {
        var elsWithClass = [];
        var els = document.getElementsByTagName('*');
        var len = els.length;
        var r = new RegExp("(^|\\\\s)"+c+"(\\\\s|$)");
        for (i = 0, x = 0; i < len; i++) {
            if ( r.test(els[i].className) ) {
                elsWithClass[x] = els[i];
                x++;
            }
        }
        return elsWithClass;
    }
     
    var els = getElementsByClass('test');
     
    for (var i=0;i<els.length;++i) {
        var hoverClass = ' green';
        var clickClass = ' red';
        els[i].onmouseover = function() {
            this.className += hoverClass;
        }
        els[i].onmouseout = function() {
            this.className = this.className.substr(0,this.className.length-hoverClass.length);
        }
        els[i].onclick = function() {
            this.className = (this.className.substr(this.className.length-clickClass.length)==='clickClass') ? this.className.substr(0,this.className.length-clickClass.length) : this.className+clickClass;
        }
    }
    James Padolsey
    末末末末末末末末末末末末末末末末末末末
    Awesome JavaScript Zoomer (demo here)
    'Ajaxy' - Ajax integration solution (demo here)

  6. #6
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    blahblahblah
    Posts
    1,447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Jimmy... Whoa... rep++

    Just a few questions about your code, if I may

    Code JavaScript:
        var r = new RegExp("(^|\\\\s)"+c+"(\\\\s|$)");
        for (i = 0, x = 0; i < len; i++) {
            if ( r.test(els[i].className) ) {
                elsWithClass[x] = els[i];
                x++;
            }
        }

    I'm not quite sure what is going on here. RegExp is a Javascript object, correct? And one of its method is "test"? Is className a DOM function? As you can see, even after going through the sticky thread and its list of articles, I'm still quite unsure about how Jscript works and thinks.

    Thanks again

  7. #7
    Function Curry'er JimmyP's Avatar
    Join Date
    Aug 2007
    Location
    Brighton, UK
    Posts
    2,006
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The variable, r, defines a regular expression (1,2,3) (essentially a pattern) which we can test a string against. You could just do something like, if(els[i].className=='watever') but that would limit it's effectiveness as a function - It wouldn't allow you to test for a class against multiple defined classes. (e.g. <div class="green big important"></div>).

    Commented version:
    Code JavaScript:
        // New regular expression to test against:
        var r = new RegExp("(^|\\\\s)"+c+"(\\\\s|$)"); 
        // Starts loop:
        for (i = 0, x = 0; i < len; i++) {
            // Tests currently selected element and tests for the specified class:
            if ( r.test(els[i].className) ) {
                 // This object has the class so it is assigned to new array of objects called "elsWithClass":
                elsWithClass[x] = els[i];
                x++; 
            }
        }

    Oh and I haven't learnt how to write regular expressions off hand so don't ask me what all that stuff means (\\\\s|etc. etc.) . Have a look at the links - they should be helpful.
    James Padolsey
    末末末末末末末末末末末末末末末末末末末
    Awesome JavaScript Zoomer (demo here)
    'Ajaxy' - Ajax integration solution (demo here)

  8. #8
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,718
    Mentioned
    103 Post(s)
    Tagged
    4 Thread(s)
    Normally the regex would be (^|\s)classname(\s|$) which checks for the classname that has before it whitespace (or is the start of the string) and has whitespace after it (or is the end of the string)

    I'm not sure if all the slashes in the original are required though.

    The "(^|\\\\s)"+c+"(\\\\s|$)" will be converted to /(^|\\s)classname(\\s|$)/ and the double backslash turns it into a literal backslash, which will match "\s classname \s" which isn't what is wanted.

    You should instead use

    Code javascript:
    var r = new RegExp("(^|\\s)"+c+"(\\s|$)");

    so that the "(^|\\s)"+c+"(\\s|$)" turns into /(^|\s)classname(\s|$)/ which can match any one of the following
    "classname"
    "... classname"
    "classname ..."
    "... classname ..."
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  9. #9
    Function Curry'er JimmyP's Avatar
    Join Date
    Aug 2007
    Location
    Brighton, UK
    Posts
    2,006
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Paul, all that mumbo-jumbo is totally lost on me ... I got this particular regex from Dustin Diaz's site... It's quite an old post though...
    - Thanks for the explanation/expansion though.
    James Padolsey
    末末末末末末末末末末末末末末末末末末末
    Awesome JavaScript Zoomer (demo here)
    'Ajaxy' - Ajax integration solution (demo here)

  10. #10
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    blahblahblah
    Posts
    1,447
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the explanation Paul.

    One more question on the original code:

    Code:
    els[i].onmouseover = function() {        this.className += hoverClass;    }    els[i].onmouseout = function() {        this.className = this.className.substr(0,this.className.length-hoverClass.length);    }    els[i].onclick = function() {        this.className = (this.className.substr(this.className.length-clickClass.length)==='clickClass') ? this.className.substr(0,this.className.length-clickClass.length) : this.className+clickClass;    }
    If I understand the code correctly, what you do in here is some string manipulation to tell the browser to add/remove classes.

    Which leads me to a Javascript mentality question when it comes to methods, functions etc.

    Code:
    this.className = this.className.substr(0,this.className.length-hoverClass.length);    }    els[i].onclick
    What is "className" to this: a function? a method? Same question for "onClick". And how would you name substr in "this.className.substr": a function?


  11. #11
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,718
    Mentioned
    103 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by jjshell View Post
    What is "className" to this: a function? a method? Same question for "onClick". And how would you name substr in "this.className.substr": a function?
    Elements have a className property

    Elements have an onclick property that contains a function or a function reference

    className returns a string, so from the string object you have the substr method

    A property is a value, whereas a method is a function.

    All elements inherit from the Elements object, so I could add a new method to Elements.prototype that would apply to all elements

    Code javascript:
    Elements.prototype.insertAfter = function (newElement, referenceElement) {
        ...
    }
    var el = document.getElementById('myId');
    var newEl = document.createElement('p');
    el.parentNode.insertAfter(newEl, el);
    // <div id="myId"></div>
    // <p></p>
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  12. #12
    Guru in training bronze trophy SoulScratch's Avatar
    Join Date
    Apr 2006
    Location
    Maryland
    Posts
    1,838
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Meh, all that regex is useless IMO since you can just replicate the same effect with string concatenation with white space and indexOf, and out of hundreds of web pages I've seen I haven't seen a tab between class name values, nor newline/carriage return, etc so I don't really run into the "backend might generate special characters" between argument

    eg ' ' + classValue + ' '.indexOf(' foo ') != -1

  13. #13
    SitePoint Addict
    Join Date
    Dec 2007
    Posts
    207
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by JimmyP View Post
    Code JavaScript:
    function getElementsByClass(c) {
        var elsWithClass = [];
        var els = document.getElementsByTagName('*');
        var len = els.length;
        var r = new RegExp("(^|\\\\s)"+c+"(\\\\s|$)");
        for (i = 0, x = 0; i < len; i++) {
            if ( r.test(els[i].className) ) {
                elsWithClass[x] = els[i];
                x++;
            }
        }
        return elsWithClass;
    }
     
    var els = getElementsByClass('test');
     
    for (var i=0;i<els.length;++i) {
        var hoverClass = ' green';
        var clickClass = ' red';
        els[i].onmouseover = function() {
            this.className += hoverClass;
        }
        els[i].onmouseout = function() {
            this.className = this.className.substr(0,this.className.length-hoverClass.length);
        }
        els[i].onclick = function() {
            this.className = (this.className.substr(this.className.length-clickClass.length)==='clickClass') ? this.className.substr(0,this.className.length-clickClass.length) : this.className+clickClass;
        }
    }
    When using a custom solution you should sniff for document.getElementsByClassName as the new versions of all 3 W3C-compat browsers support it (ff, safari, opera).

    Quote Originally Posted by JimmyP View Post
    Paul, all that mumbo-jumbo is totally lost on me ... I got this particular regex from Dustin Diaz's site... It's quite an old post though...
    - Thanks for the explanation/expansion though.
    If you're posting something from a website it is part of internet etiquette to link to it.

    Believe it or not, you can even violate copyright rules by not doing so.

    Quote Originally Posted by pmw57 View Post
    Elements have a className property

    Elements have an onclick property that contains a function or a function reference

    className returns a string, so from the string object you have the substr method

    A property is a value, whereas a method is a function.

    All elements inherit from the Elements object, so I could add a new method to Elements.prototype that would apply to all elements

    Code javascript:
    Elements.prototype.insertAfter = function (newElement, referenceElement) {
        ...
    }
    var el = document.getElementById('myId');
    var newEl = document.createElement('p');
    el.parentNode.insertAfter(newEl, el);
    // <div id="myId"></div>
    // <p></p>
    I think you mean Element.prototype.

    Either way I don't think it would work on IE.
    mmj

  14. #14
    Function Curry'er JimmyP's Avatar
    Join Date
    Aug 2007
    Location
    Brighton, UK
    Posts
    2,006
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by M-M-J View Post
    When using a custom solution you should sniff for document.getElementsByClassName as the new versions of all 3 W3C-compat browsers support it (ff, safari, opera).
    Sniffing for and using the built in method just means more unnecessary code. I know it's the "right" thing to do but less code = better!

    Quote Originally Posted by M-M-J View Post
    If you're posting something from a website it is part of internet etiquette to link to it.
    Believe it or not, you can even violate copyright rules by not doing so.
    I did link to it in the post you quoted. Plus it wasn't a direct copy - All I liberated was the regex pattern! ... You really think anyone would ever claim copyright infringement on that???
    James Padolsey
    末末末末末末末末末末末末末末末末末末末
    Awesome JavaScript Zoomer (demo here)
    'Ajaxy' - Ajax integration solution (demo here)

  15. #15
    SitePoint Addict
    Join Date
    Dec 2007
    Posts
    207
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by JimmyP View Post
    Sniffing for and using the built in method just means more unnecessary code. I know it's the "right" thing to do but less code = better!
    Unnecessary? It will make a huge performance difference. It will also be a live NodeList, not a static Array.

    Quote Originally Posted by JimmyP View Post
    I did link to it in the post you quoted. Plus it wasn't a direct copy - All I liberated was the regex pattern! ... You really think anyone would ever claim copyright infringement on that???


    No, I don't think so.

    Quote Originally Posted by jjshell View Post
    Hi,

    I'm getting accustomed to using jQuery, without really knowing Javascript.

    But this is it. I want to learn Javascript. I've read a few interesting articles about the language foundations, but I've lost hours trying to do simple things.

    I was wondering how hard it would be to translate this jQuery snippet to plain Javascript. I would for sure make tremendous progress if I can get a look at a clear and consise approach to such common problems.

    Code:
     $(document).ready(function() {
     
     
       $(".test").hover(function() {
         $(this).addClass("green");
       },function(){
         $(this).removeClass("green");
       });
    
       $(".test").click(function() {
         $(this).toggleClass("red");
       });
       
       
     });
    HTML Code:
    <div class="test">
    </div>
    Regards

    -jj.
    If you're using the new versions of the 3 w3c compat browsers then its quite simple.

    Code javascript:
    document.addEventListener("DOMContentLoaded", function() {
    	var el = document.getElementsByClassName("test"), l = el.length;
    	while (l--){
    		el[l].onmouseover = function(){
    			this.className = this.className + " green";
    		};
    		el[l].onmouseout = function(){
    			this.className = this.className.replace("green", "");
    		};
    		el[l].onclick = function(){
    			if (~this.className.indexOf("red"))
    				this.className = this.className.replace("red", "");
    			else
    				this.className = this.className + " red";
    		};
    	}
    }, false);
    mmj

  16. #16
    Guru in training bronze trophy SoulScratch's Avatar
    Join Date
    Apr 2006
    Location
    Maryland
    Posts
    1,838
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by JimmyP View Post
    Sniffing for and using the built in method just means more unnecessary code. I know it's the "right" thing to do but less code = better!
    Sniffing for a native method is VERY IMPORTANT (in regards to prototoypes) because you could also end up mixing your code in with a library that has also modified the method that you're using, and you'd be overriding a method that the library is dependent upon.

    Less code is NOT better, if a native method has a function with 200 lines of code, calling it would be faster than implementing a custom function.

    document.addEventListener("DOMContentLoaded", function() {
    Hm, won't you get the same result by attaching it to the window object (on dom ready) ? And these would only work in the latest Gecko, Opera 9, and Safari 3?


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
  •