JavaScript Events

Filed under technical on Wednesday, 22 June 2005 at 13:31.

Jens’s PHP lamentation brought up a good question: Why isn’t JavaScript more popular outside of client-side browser scripting? I think it may have to do with the experiences software programmers have when dealing with JavaScript in the web browser world.

JavaScript is actually a quite deceptive language. It’s much more powerful than it first appears. I was quite surprised to learn that JavaScript actually has quite a bit in common with some of the functional languages I’ve learned—you can even curry JavaScript functions! Of course, many web programmers aren’t aware of the object-oriented side of JavaScript or many of its other advanced features—even if they are, they don’t use them often. Software programmers therefore rarely encounter these advanced features in the wild. But even when software programmers become aware of the advanced features, there are problems.

My current problem with JavaScript is not actually specific to the language, but to its usage with DOM events. In creating a class, I often want member functions which handle events. I tend to use the .prototype. construct to create member functions, but when events call member functions of an object, the this which those functions have refers back to the object on which the event fired (typically some HTML element), not the instance of the class in which the member function resides!

This can be worked around by having a var self = this; statement in my constructor, and placing all of my event-handling functions within my constructor function, but this is certainly less than ideal.

Is there a way I can create event handlers in the way I like (outside of the constructor function), and yet have a pointer back to their owning object? Global variables are not a proper, well-encapsulated solution.

8 Responses to “JavaScript Events”

  1. Assuming your constructor is for an object Foo, and at some point in your file you define Foo.prototoype.handleClick, is there a reason why you can’t have this:

    function Foo() {
    var self = this;
    var node = ...

    node.onclick = function(event) {self.handleClick(event);}
    }

    Foo.prototype.handleClick = function(event) {
    ...
    }

    Also, look into the call() and apply() methods on function objects, they’re handy.

  2. Aha, that is a slightly better hack around it than what I was doing, yes.

    It still kind of sucks to have to do that for every event handler, but it does keep the majority of my code out of the constructor. It’s still not an actual solution, but it’s a step above what I was doing before. Thanks.

  3. It looks like if I want to do serious event work in JavaScript I should be creating my own Event object rather than using the “HTMLEvents” object. After doing that it seems I’ll have to see what this refers to in that situation.

  4. Just as a point of interest, the Synchronet BBS package (for those that remember the BBS days) now uses JavaScript to create BBS modules. The software is GPLed and still under active development. You can check it out at http://www.synchro.net. The author originally made his own programming language years ago to handle the BBS modules (the language was called Baja), but began redoing everything with JavaScript recently. It really is pretty cool. :)

  5. I’ve found this problem as well, and my solution was to create closures. Example:


    function foo() {
    var elementID = "x"; // Somehow provide a reference to the HTMLElement

    function handleClick(){
    alert(this.elementID);
    };
    }

    bar = new foo();
    element = getElementById(bar.elementID);
    element.prep =
    function(obj) {
    return function() {
    obj.handleClick();
    };
    };
    element.onclick = element.prep(bar);

    This creates binds a closure to the HTMLEvent that sends the handleClick() message to the object you pass into prep(). You can reuse the variables “bar” and “element” all you like and it won’t tamper with the closures. So far it’s been working for me.

  6. Mihai’s solution is a bit better for the circumstances I’m dealing with, since I have a lot of different event handlers. It’s always good to have options, though. Thanks!

  7. Create a method reference passing in the “object” you wish to refer to as “this” in the event handler

    Eg.

    In Constructor:
    this.oText.onblur = createMethodReference(this, “TextBox_OnBlur”);

    function createMethodReference(object, methodName) {
    return function () {
    object[methodName].apply(object, arguments);
    };
    }

    DropDownSelection.prototype.TextBox_OnBlur = function()
    {
    var e = window.event;
    if(this.isDropDownOpen && !this.isMouseOverDropDown)
    this.Reset();
    }

    “this” now refers to my object in the event handler, not the calling object.

  8. Mihai’s solution didn’t work for me, but ben’s did! Nice work there!

    I’m so relieved someone else was having this problem. I thought my debugger was broken since it displayed the wrong reference for this! :)

Leave a Reply

missig.org/julian/blog
Julian Missig - jabber:julian@jabber.org - aim:xvirge
julian/blog is powered by WordPress
Entries (RSS) and Comments (RSS).