views:

121

answers:

2

Im using event handlers from a framework (prototype to be specific) to attach listerners to certain elements of a page like this:

//html
<a href="?default=1" class="default">Set Default</a>
//js
document.observe('dom:loaded', function(){
        //get all elements with d 'default' classname
        for(i = 0;i < document.getElementsByClassName('default').length;i++)
        {
                s = document.getElementsByClassName('default')[i];
                //attach an onclick event
                s.observe('click', function(e){
                        //prevent the default action (i.e loading the page)
                        e.preventDefault();
                        //read d link attribute
                        ref = this.readAttribute('href');
                        //and now, do it the ajax way
                        new Ajax.Request('js/ajax/handler.php'+ref, {
                                method:'get',
                                onSuccess:function(transport){}
                        });
                });
        }
});

It works well. Really well. But there is a challenge. Most times, such actions manipulates the DOM and may add one or more of the 'default' class element (i.e another Set Default somewhere). That is intentional actually. But then, the newly added 'default' class element will not have the click event attached. The shitty work around at the moment is to loop through all the 'default' classes again and re-attach the events. Any other ideas?

+2  A: 

The usual way to solve that is via event delegation. If you hook the click event on a container that holds all of these .default items, you can respond in that one handler:

document.observe('click', function(event) {
    var elm;

    elm = event.findElement('.default');
    if (elm) {
        // do your nifty stuff with the element
    }
});

It doesn't have to be document if they share some higher-up container. Docs for Event#findElement are here.

BTW, there's a big performance problem with your for loop. You're calling document.getElementsByClassName on every iteration! If you use event delegation, that loop goes away anyway, but if that doesn't work for whatever reason, call it once and then loop through the result:

var defaults = document.getElementsByClassName('default');
for (i = 0; i < defaults.length; i++)
T.J. Crowder
This rocks. Thanks a bunch!
ray
+1  A: 

You could listen to all click events on the page, then use the event's target to determine if the user clicked on an element with the className "default".

Daniel Lew
Thanks for the reply. Helped a lot
ray