SitePoint Sponsor

User Tag List

Results 1 to 20 of 20
  1. #1
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Trying to add event listeners on load to multiple elements using the class name

    I have found various scripts and put together to try and achieve this.

    The script below should register event listeners on load, but I am trying to do it for when I need multiple items with the same class name, e.g. a tooltip, or to ensure every button on the site had an Ajax loading image applied.

    I believe I have everything sorted except 'the add_event_multiple_classes' function in my script.

    Please help complete this and is this the best way to do it? It seem a lot easy to just use inline JS considering how much code this is taking.

    Code:
    if (typeof getElementsByClassName !== "function") {
      function getElementsByClassName(findClass, parent) {
        parent = parent || document;
        var elements = parent.getElementsByTagName('*');
        var matching = [];
        for(var i = 0, elementsLength = elements.length; i < elementsLength; i++){
          var regex = new RegExp('\b' + findClass + '\b')
          if (elements[i].className.match(regex)) {
            matching.push(elements[i]);
          }
        }
        return matching;
      }
    }
    
    
    if (window.addEventListener)
    addEvent = function(ob, type, fn ) {
    **ob.addEventListener(type, fn, false );
    };
    else if (document.attachEvent)
    addEvent = function(ob, type, fn ) {
    **var eProp = type + fn;
    **ob['e'+eProp] = fn;
    **ob[eProp] = function(){ob['e'+eProp]( window.event );};
    **ob.attachEvent( 'on'+type, ob[eProp]);
    };
    
    
    function on_load_scripts() {
    	
    	//set some event listeners
    	
    	addEvent(document.getElementById('an-id'), 'click', some_javascript);
    	
    	add_event_multiple_classes ( 'submit-button', 'click', button_loading_image );
    	
    }
    
    function add_event_multiple_classes(class, action, fn) {
    
    	// THIS IS THE AREA I AM STRUGGLING ON
    	
    	//somehow get hold of all the classes with the provided class name and convert so
    	//they can all be referenced and have an event listener registered to them.
    	
            // What about searching for all matching class names and adding a unique id next to it (how would I do this?)
    
    	/// ??????????????????????????
    
    	for/foreach() { // for every class with the 'class' name
    
    		addEvent(xxxxxxxxxxx, action, fn);
    
    	}
    
    }
    
    function some_javascript() {
    
    	//perform action
    
    }
    
    function button_loading_image() {
    
    	//perform action
    
    }
    
    addEvent(window, 'load', on_load_scripts);

  2. #2
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,705
    Mentioned
    102 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by johnsmith153 View Post
    I am trying to do it for when I need multiple items with the same class name, e.g. a tooltip, or to ensure every button on the site had an Ajax loading image applied.
    The add_event_multiple_classes function can make good use of the getElementsByClassName function, wich will give you an array of elements that match the class name. YOu can then loop through those elements applying the event function to them.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  3. #3
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the response,

    I've sort of moved on with this and now have two problems:

    (1) I'm trying to add an event, but specifying the function seems a problem.

    My script is slightly different, but it is the same as this:

    document.addEventListener('load', your_function, false);

    The problem is I want to use a variable instead of your_function.

    Somehow I need the value in a variable to be the function name (so I have: var $a = "my_function"; and I want to execute the function named 'my_function' from this)

    (2) I also understand the mouse event is passed automatically to the function.

    So in this: document.addEventListener('load', your_function, false);
    ...it's automatically passed to 'your_function'.

    I need to get the div/tag anything that was clicked on so I can then go and do:

    x.className = 'new_class_name'; (with x being the reference to what was clicked on).

    Thanks for any help.

  4. #4
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,705
    Mentioned
    102 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by johnsmith153 View Post
    Somehow I need the value in a variable to be the function name (so I have: var $a = "my_function"; and I want to execute the function named 'my_function' from this)
    No, don't do that. function names can be assigned as variables too.

    Code javascript:
    function my_function() {
     
    }
    var $a = my_function;

    Or

    Code javascript:
    var $a = function () {
        ...
    };

    Quote Originally Posted by johnsmith153 View Post
    (2) I also understand the mouse event is passed automatically to the function.

    So in this: document.addEventListener('load', your_function, false);
    ...it's automatically passed to 'your_function'.

    I need to get the div/tag anything that was clicked on so I can then go and do:

    x.className = 'new_class_name'; (with x being the reference to what was clicked on).
    Here's the standard technique for doing that:

    Code javascript:
    var eventHandler = function (evt) {
        evt = evt || window.event;
        var targ = evt.target || evt.srcElement;
        ...
    }

    Once you have the target element that was clicked on, you can then go ahead with targ.className = ...
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  5. #5
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks Paul, you clearly know your stuff.

    As for the first one, I don;t really want to do it as a variable it's just that my script ended up that way.

    This is what I have:

    Code:
    
    var events_list = new Array();
    events_list['click'] = "perform_action";
    events_list['mouseover'] = "something_else";
    add_event_multiple_classes ( 'class-name', 'new-id-name', events_list );
    	
    
    function add_event_multiple_classes(classNm, new_id_name, events_list) {
    
       counter = 1;
    
       var elements = getElementsByClassName(document, classNm),
           n = elements.length;
       for (var i = 0; i < n; i++) {
         var e = elements[i];
         this_new_id_name = new_id_name + "_" + counter++;
         //add id element to it
    	 e.id = this_new_id_name;
         //add events
         for (action in events_list) {
           fn = events_list[action];
       	   addEvent(document.getElementById(this_new_id_name), action, **** THIS NEEDS TO BE THE VALUE IN VARIABLE fn *****);
       	 }
       }
    	
    }
    
    function perform_action() {
    
    }
    Any ideas?

  6. #6
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,705
    Mentioned
    102 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by johnsmith153 View Post
    Any ideas?
    After some simplifications, we end up with this:

    Code javascript:
    function addEventsToElement(el, eventsList) {
        var action;
        for (action in eventsList) {
            if (eventsList.hasOwnProperty(action)) {
                addEvent(el, action, eventsList[action]);
            }
        }
    }
     
    function addEventMultipleClasses(className, eventsList) {
        var elements = getElementsByClassName(document, className),
            elementsLength = elements.length,
            i;
        for (i = 0; i < elementsLength; i += 1) {
            addEventsToElement(elements[i], eventsList);
        }
    }
     
    function performAction() {
     
    }
     
    function somethingElse() {
     
    }
     
    addEventMultipleClasses('class-name', {
        click: performAction,
        mouseover: somethingElse
    });

    As an example of one of the changes, you shouldn't declare variables in the middle of a function. Even when they're declared in the middle, their declaration is automatically hoisted to the top of the function. So to reduce confusion, always declare variables in one block at the start of the function.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  7. #7
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Perfect. Thanks again, and thanks for the extra advice.

  8. #8
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I thought it best to continue this thread as my new question partly relates to this.

    I simply want to create a standard HTML link but also append JS functionality.

    <a href="?page=2">Show More</a>

    I want to use the code above to append a simple show_more() function, which I can do but it always fires the ?page=2 part after running the JS. I know a simple onclick="return false" sorts this out but considering I'm trying to do this properly that obviously should;t be used.

    If I do this:

    function show_more() {
    //the show more code

    return false;
    }

    ..then the return false in the function does nothing.

    Where do I put the return false to prevent the HTML hyperlink from firing if JS is enabled?

  9. #9
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,705
    Mentioned
    102 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by johnsmith153 View Post
    Where do I put the return false to prevent the HTML hyperlink from firing if JS is enabled?
    That depends on how you are attaching the show_more function to the event.

    The most appropriate way is to attach it to the onclick event of the link itself. Not via an inline HTML event attribute, but via scripting instead.

    HTML Code:
    <a id="showmore" href="?page=2">Show More</a>
    Code javascript:
    function show_more() {
        ...
    }
     
    document.getElementById('showmore').onclick = show_more;

    Notice that it's show_more without parenthesis that is assigned to the onclick event.
    If it were show_more() with the parenthesis, then you would be assigning to the event the returned value from the function, that being undefined or false, depending on if the function returns nothing or false.

    So instead, by assigning just a reference to the function itself to the onclick event, the function can return false to prevent the default behaviour (of the web browser following the link) from occurring.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  10. #10
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks again Paul.

    I am hoping to use the code you posted on Dec 23, 2011 at 20:24 in this topic.

    Hopefully, I can just add this to the set of code:

    Code:
    <script>
    
    addEventsToElement ('js-show-more', {click: show_more} ); // note, I definitely use show_more and not show_more()
    
    function show_more() {
    
     // do the show more stuff
    
     return false;
    
    }
    
    </script>
    
    <a href="?pg=2" class="js-show-more">SHOW MORE</a>
    ...If I do this, the JS runs, but it also fires the ?pg=2 part. Is it possible to do this with the set of code you provided rather than using document.getElementById('showmore').onclick = show_more; (although I would guess both should do the same thing, so I'm a little confused there)?

    Thanks again for your help!

  11. #11
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,705
    Mentioned
    102 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by johnsmith153 View Post
    ...If I do this, the JS runs, but it also fires the ?pg=2 part. Is it possible to do this with the set of code you provided rather than using document.getElementById('showmore').onclick = show_more; (although I would guess both should do the same thing, so I'm a little confused there)?

    Thanks again for your help!
    Can you put up a sample page so that some testing can occur? There is a jsfiddle.net. If you do, in the choose framework part on the left, change onload to no wrap (body) and change mootools to be instead no library.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  12. #12
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi,

    Is this ok as a test?

    http://page-test.co.uk/test.html

  13. #13
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,705
    Mentioned
    102 Post(s)
    Tagged
    4 Thread(s)
    Oh that's right, you're using the advanced event registration technique here, which is hampered by a Microsoft problem.
    On Internet Explorer when attachEvent is used, the this keyword becomes broken and points to the window object, instead of the element that triggered the event.

    So, we can make use of either the preventDefault() method from the event, or for IE we can set the returnValue property on the event itself.

    The following should do the trick:

    Code javascript:
    function run_test(evt) {
        evt = evt || window.event;
        evt.preventDefault();
        window.event.returnValue = false;
        return false;
    }
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  14. #14
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks Paul.

    So, would this be ok (for all browsers etc.)?

    Code:
    function run_test(evt) {
     alert("TEST 2");
     return return_false(evt);
    }
    
    
    function return_false(evt) {
     evt = evt || window.event;
     evt.preventDefault();
     window.event.returnValue = false;
     return false;   
    }
    ...I can then use the return_false() function for all other uses.

    I've updated http://page-test.co.uk/test.html and it seems to work fine.

  15. #15
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,705
    Mentioned
    102 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by johnsmith153 View Post
    Thanks Paul.

    So, would this be ok (for all browsers etc.)?
    It would be, yes. Although you may want to change the function name from return_false to prevent_default, or some other name that more appropriately describes the purpose of the function.

    That way, you'll have a better way to understand what the code is doing, without needing to track down and study the function, when you see:

    Code javascript:
    return prevent_default(evt);
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  16. #16
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks Paul,

    I've changed it on my actual code, although I thought return_false was a good name for it!! (obviously not, and I understand now).

    --

    I have another issue I have just come across using the code Paul helped me with above.

    I need to pass a value from PHP using the set of functions at http://page-test.co.uk/test.html but can't see how I would do it.

    So,

    Code:
    <input type="button" onclick="run_function_name('<?php echo $value_from_php; ?>')" />
    ... would work fine, but how would I fit that into the code at http://page-test.co.uk/test.html? (snippet shown below):

    Code:
    add_event_by_class('test', {click: run_test} );
    ...especially since I include the JS in external files.

    ...even if it wasn't included in an external JS file, I'm not sure if the below would work anyway as I don't think you can include the brackets:

    Code:
    add_event_by_class('test', {click: run_test('<?php echo %value_from_php; ?>')} );
    The only way I can think of is to include values from PHP in a hidden text field and call them from the function that the above snippet runs (so in this case the function is called 'run_test').

    Thanks in advance.

  17. #17
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,705
    Mentioned
    102 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by johnsmith153 View Post
    I have another issue I have just come across using the code Paul helped me with above.

    I need to pass a value from PHP using the set of functions at http://page-test.co.uk/test.html but can't see how I would do it.
    One it is set as the value of the checkbox, any scripting code can retrieve that value from the checkbox, so you only need to set it the once.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  18. #18
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I've just realised, this does't work in IE7 or Firefox 8 (not tested later versions of IE, but guessing if I get IE7 then rest would be ok).

    No problem in the latest Chrome / Safari.

    I've stripped out everything from the test below to isolate as best as possible.

    http://page-test.co.uk/test.html

  19. #19
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,705
    Mentioned
    102 Post(s)
    Tagged
    4 Thread(s)
    That will be the evt.preventDefault()

    You can prevent older web browsers from having troubles with that, by checking if it exists first before running it.

    Code javascript:
    if (evt.preventDefault) {
        evt.preventDefault();
    }
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  20. #20
    SitePoint Addict
    Join Date
    Sep 2008
    Posts
    341
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks again!!


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
  •