views:

253

answers:

2

I've bumped up against this before and I need the help of someone smarter than me!

How can I attach an event of an element to a method of a class? More specifically, the same class? Is there a better way?

Using a Qt widget style approach, I've been trying to create self-contained "widget" objects in javascript. I'm using the Prototype javascript framework and building my widget as a class. Then, using Event.observe, I've tried to attach the event to a method of the class. But the Event assignment unbinds the assigned method. Here's an example of a simple table I'm trying to build that has clickable column headers:

 Objectify.Grid.Table = Class.create({
    initialize: function(headers) {
        this.columns = headers;
        this.rows = [];
    }, 
    addRow: function(GridData) {
        var len = this.rows.push(GridData);
        return len-1;
    },
    getRow: function(rowIndex) {
        return this.rows[rowIndex];
    },
    build: function(parent) {
        this.mainTable = new Element('table',{'class':'Objectify-Grid'});
        $(parent).update(this.mainTable);

        var tableBody = new Element('tbody',{});
        this.mainTable.update(tableBody);

            var headerRow = new Element('tr',{'class':'Objectify-Grid-header-row'});
            tableBody.update(headerRow);

                this.columns.each(function(val,id) {
                    var hcell = new Element('td',{'class':'Objectify-Grid-header-cell'}).update(val);
                    headerRow.insert(hcell);
                    // EVENT ASSIGNMENT //
                    hcell.observe('click',this.respondToClick);
                    /////////////////////
                }.bind(this));

      this.rows.each(function(GridData,id) {
       var row = new Element('tr',{'class':'Objectify-Grid-row','id':'Objectify-Grid-row'+id});
       tableBody.insert(row);

        this.columns.each(function(columnName,index) {
         var cell = new Element('td',{'class':'Objectify-Grid-cell'}).update(GridData.getValue(columnName));
         row.insert(cell);
        });

      }.bind(this));
    },
    // RECEIVING METHOD //
    respondToClick: function(event) {
     var columnName = event.element().innerHTML;
     // "this" is no longer bound in this method
        this.sortColumnAsc(columnName); // [ERROR]
    }
});
A: 

I'm not too familiar with Prototype, but what does this refer to in the respondToClick event handler? If I had to guess, I'd say it referred to the clicked DOM element, and not the object instance you wanted.

Perhaps you can assign the grid to a property the DOM element and reuse that property during the respondToClick function, as in:

myDOMElement.someProperty = grid;

//and later

this.somePropery.sortColumnAsc(columnName);
David Andres
Thanks Dandres, but "this" I was hoping would refer to the class that the method was a part of.
Scott Willman
+3  A: 

I think that you should do this :

hcell.observe('click',this.respondToClick.bindAsEventListener(this));

and the second argument of the "each" method is the object to bind the function to, so you can do this:

array.each(someFunction, this);

instead of

array.each(someFunction.bind(this));
Fabien Ménager
looks right to me
seengee
Thanks Fabien, I should have dug a little deeper in the docs before posting!http://www.prototypejs.org/api/event/observe
Scott Willman