views:

2164

answers:

6

This is a question I ran into about expanding on an element's JavaScript onchange event. I have several select elements that conditionally will have one onchange event attached to each of them (when they change to specific values, it hides/unhides certain elements). I want to conditionally add or append to another onchange event so they set a global variable if they do change without modifying or disabling the previous function already attached to them. Is there a way to "append" an additional function or add more functionality onto the already existing one?

Here is what I believe an example would be like:

<select id="selectbox1">
    <option>...</option>
    <option>...</option>
</select>

if (<certain conditions>) {
    document.getElementById("selectbox1").onchange = function () { 
        //hides elements to reduce clutter on a web form ...
    }
}
....
if (<other conditions>) {
    document.getElementById("selectbox1").onchange = function2 () {
        //set global variable to false
    }
}

Alternatively I'd like to simply add the 1-liner "set global variable to false" to the original function.

+3  A: 

You can cheat by simply having a composite function that calls the other functions.

document.getElementById("selectbox1").onchange = function() {
    function1();
    function2();
}

You can also use the observer pattern, described in the book Pro JavaScript Design Patterns. I have an example of its use in an article (here).

//– publisher class — 
function Publisher() { 
    this.subscribers = []; 
};

Publisher.prototype.deliver = function(data) { 
    this.subscribers.forEach(function(fn) { fn(data); }); 
};

//– subscribe method to all existing objects 
Function.prototype.subscribe = function(publisher) { 
    var that = this; 
    var alreadyExists = publisher.subscribers.some(function(el) { 
        if (el === that) { 
            return; 
        } 
    });

    if (!alreadyExists) { 
        publisher.subscribers.push(this); 
    } 
    return this; 
};
Joel Martinez
+1  A: 

Have a look at addEventListener - https://developer.mozilla.org/en/DOM/element.addEventListener

Daniel A. White
A: 

You want to look at the addEventListener() and attachEvent() functions (for Mozilla-based browsers and IE respectively).

Take a look at the docs for addEventListener() and attachEvent().

var el = document.getElementById("selectbox1");

try { //For IE
    el.attachEvent("onchange", function(){ code here.. });
}
catch(e) { //For FF, Opera, Safari etc
    el.addEventListener("change", function(){ code here.. }, false);
}

You can add multiple listeners to each element, therefore more than one function can be called when the event fires.

Perspx
+2  A: 

Can you use jQuery? This will allow you to bind/manipulate/unbind events pretty easily. The only hitch is event handlers are activated in the order they are bound.

if (<certain conditions>) {
   $("#selectbox1").bind("change", eventdata, function1);
}

if (<other conditions>) {
   $("#selectbox1").bind("change", eventdata, function1);
}

And, you can also look into triggering custom events, if your needs are complex. For example, instead of "interpreting" onChange, maybe there is a way to specifically trigger custom events. See the last example on jQuery's page.

alphadogg
I can use jQuery but I've never used it before. Avoiding the learning curve for now if possible.
Brian
There is likely more of a learning curve to trying to figure out all the cross-browser and various innards of JS and browsers. And, jQuery is pretty easy to pick up, and worth the small investment...
alphadogg
jQuery is going to be my next project for sure! I want to try to pick it up in the next month or two, but before COB today I would like to get a solution out.
Brian
+2  A: 

If you use jQUery you would have something like

<select id="selectbox1">
    <option>...</option>
    <option>...</option>
</select>

if (<certain conditions>) {
    $("#selectbox1").change(function () { 
        //hides elements to reduce clutter on a web form ...
    });
}
....
if (<other conditions>) {
    $("#selectbox1").change(function () { 
        //set global variable to false
    });
}

This will mostly take care of browser compatibility as well.

Greg Adamski
+1  A: 

There are currently three different methods for defining event handlers (a function which is fired when a certain event is detected): the traditional method, the W3C method, and the Microsoft method.

Traditional method

In the traditional method, event handlers are defined by setting the on*event* property of an element in Javascript (as you are doing in your example code), or by setting the on*event* attribute in an HTML tag (such as <select onchange="...">). While this is the simplest method to use, its use is generally frowned upon now, because as you have discovered, it is rather rigid -- it is not easy to add and remove event handlers to an element that already has an event handler attached. As well, it is not considered proper practice anymore to mix javascript in with HTML, but rather it should be contained within or loaded via a <script> tag.

W3C / Microsoft methods

The W3C (World Wide Web Consortium) and Microsoft both define their own event models. The two models works essentially the same way, but use different syntaxes. The Microsoft model is used in Internet Explorer, and the W3C model is used in other browsers (Firefox, Opera, Safari, Chrome, etc.). In both of these models, there are functions provided to add event handlers (addEventListener for W3C, attachEvent for Microsoft) and remove event handlers (removeEventListener / detachEvent). This allows you to dynamically add and remove specific handlers to an element; in your case, you could add the first handler based on the first condition and the second based on the second condition. The "problem" with these methods is that there are two of them, and thus both methods need to be used in order to ensure that your event handler will be registered in all browsers (there are also a few subtle differences between the two models, but those differences are not important to the scope of this question). In fact, if you look, you will find a large number of "addEvent" functions which use both methods as necessary (and generally fall back to the traditional method for older browsers). For example, a contest was run on the QuirksMode blog back in 2005 to build the best "addEvent" function, the result of which (along with the winning function) you can see here.

As well, if you use a javascript library such as Prototype or jQuery, they come with built in event handling functions that will take care of the above for you.

Daniel Vandersluis