views:

274

answers:

1

What I'm trying to do is create a class that I can quickly attach to links, that will fetch and display a thumbnail preview of the document being linked to. Now, I am focusing on ease of use and portability here, I want to simply add a mouseover event to links like this:

<a href="some-document.pdf" onmouseover="new TestClass(this)">Testing</a>

I realize there are other ways I can go about this that would solve my issue here, and I may end up having to do that, but right now my goal is to implement this as above. I don't want to manually add a mouseout event to each link, and I don't want code anywhere other than within the class (and the mouseover event creating the class instance).

The code:

TestClass = new Class({
    initialize: function(anchor) {
        this.anchor = $(anchor);
        if(!this.anchor) return;

        if(!window.zzz) window.zzz = 0;
        this.id = ++window.zzz;

        this.anchor.addEvent('mouseout', function() {
            // i need to get a reference to this function
            this.hide();
        }.bind(this));

        this.show();

    },
    show: function() {
        // TODO: cool web 2.0 stuff here!
    },
    hide: function() {
        alert(this.id);

        //this.removeEvent('mouseout', ?);  // need reference to the function to remove

        /*** this works, but what if there are unrelated mouseout events? and the class instance still exists! ***/
        //this.anchor.removeEvents('mouseout');

        //delete(this);  // does not work !
        //this = null; // invalid assignment!
        //this = undefined; // invalid assignment!

    }
});

What currently happens with the above code:

  • 1st time out: alerts 1
  • 2nd time out: alerts 1, 2
  • 3rd time out: alerts 1, 2, 3
  • etc

Desired behavior:

  • 1st time out: alerts 1
  • 2nd time out: alerts 2
  • 3rd time out: alerts 3
  • etc

The problem is, each time I mouse over the link, I'm creating a new class instance and appending a new mouseout event for that instance. The class instance also remains in memory indefinitely.

On mouseout I need to remove the mouseout event and destroy the class instance, so on subsequent mouseovers we are starting fresh.

I could create a helper function for this to make sure that the class is only created once for each link, something like this:

function TestClassHelper(anchor) {
    anchor = $(anchor);
    if(!anchor) return;

    if(!anchor.retrieve('TestClass')) anchor.store('TestClass', new TestClass(anchor));
    anchor.retrieve('TestClass').show();
}

<a href="some-document.pdf" onmouseover="TestClassHelper(this)">Testing</a>

I may end up implementing it this way if I have to, but I'm curious as to how I can fix the other method.

+2  A: 

This looks a lot more complex than it should be. But if you want to fix this, you need to save a reference to the bound function somewhere and later pass that to removeEvent.

For example:

// inside initialize
this.boundHandler = function() {
    this.hide();
}.bind(this)
this.anchor.addEvent('mouseout', this.boundHandler);

// inside hide    
this.removeEvent('mouseout', this.boundHandler);

See the removeEvent docs for examples of this very issue.

I wouldn't recommend event delegation here either for performance reasons. The best approach is to attach the handler in code rather than inline and only do it once, so unnecessary objects are not being created each time the user mouses over.

Anurag
Thanks for the reply. This removes the mouseout event, but as you point out I'm still creating extra objects un-necessarily, so I guess I will have to uncomplicate this as you suggest. I think I will create a single, global instance to handle all links and do something like this `<a onmouseover="myTestClass.show(this)" onmouseover="myTestClass.hide(this)">`
Rob
@Rob having a single global shared instance seems like a good option since there is no object specific state for each link here.
Anurag