Kevin Kuyl
Kevin Kuyl

Reputation: 1265

javascript events seem to get mixed up

im working on a project for which i coded a quick and dirty dom manipulation framework.. or function rather:

var $ = function(e, properties){
    var elem = document.getElementById(e) || false;

    if(!elem && properties){
        elem = document.createElement('div');
        elem.id = e;

        for(i in properties){
            switch(i){
                case 'parent':
                    properties.parent.appendChild(elem);
                break;

                case 'events': 
                    for(j in properties.events){
                        elem.addEventListener(j, function(e){
                            e.preventDefault();
                            properties.events[j](e, elem);
                        });
                    }
                break; 

                default : 
                    elem[i] = properties[i];
                break; 
            }
        }
    }
    return elem;
};

as long as im using one event listener throughout the project, everything seems to be working fine, however, when i add another element the events get mixed up, i get a click event where a contextmenu event should be emitted, things just become a mess. it seems to want to call the wrong function.

demonstration of the problem: fiddle

Upvotes: 0

Views: 85

Answers (1)

Pointy
Pointy

Reputation: 413737

Variables "i" and "j" are global. They should be declared with var in the function:

var i, j;

That won't fix it, however. Inside the event listener functions you create, there's still a reference to "j", and that's still going to be a reference from every handler to the very same variable. A variable can only have one value at a time, and that value will be whatever "j" was when the very last handler was assigned.

You need to add another layer of function call in order create a unique scope for each handler:

                    elem.addEventListener(j, function(jCopy) {
                        return function(e){
                          e.preventDefault();
                          properties.events[jCopy](e, elem);
                        };
                    }(j));

There are other ways of achieving the same thing, but they're all more or less the same idea. There are a zillion related questions on Stackoverflow.

Upvotes: 3

Related Questions