Search code examples
extjsdatagridevent-handlingdom-eventsextjs3

Redefining ExtJS events and delegating to previous implementation


I've inherited a large ExtJS3 code base and there is a "base" override of Ext.grid.CellSelectionModel's beforecellselect. I'm truncating huge swathes of code but this should provide the general idea:

Ext.override(Ext.grid.CellSelectionModel, {
    init:function() {
        Ext.grid.CellSelectionModel.superclass.init.apply(this, arguments);

        if (this.unselectableColumns || this.visuallyMimicRowSelection || this.colSpecificHandlers){
        this.on('beforecellselect', function(selModel, rowIndex, columnIndex){
            //etcetera

Subsequently however we are instantiating a CellSelectionModel, and specifying a beforecellselect listener on it as follows:

var sm = new Ext.grid.CellSelectionModel({
listeners: {
    beforecellselect : {
    fn: function(selModel, rowIndex, colIndex) {
            //etcetera

The issue is, from within the listener on the new CellSelectionModel instance, I also need to call the listener defined in the override. Because ExtJS seems to preserve an array of like-named event listeners, I'm able to delegate as follows:

selModel.events.beforecellselect.listeners[1].fn.apply(selModel, arguments);

Ok, I know I shouldn't hard code the index. But besides that is there a better, more ExtJS-y way, to do this?


Solution

  • In your case, if you know it'll be a function that will be used outside of the constructor, I would suggest adding the event handler function as a method of the CellSelectionModel instance, as shown below:

        Ext.override(Ext.grid.CellSelectionModel, {
            init:function() {
                Ext.grid.CellSelectionModel.superclass.init.apply(this, arguments);
                this.customBeforeCellSelect = function(selModel, rowIndex, colIndex) {
                    // etcetera
                };
                if (this.unselectableColumns
                    || this.visuallyMimicRowSelection
                    || this.colSpecificHandlers) {
                    this.on('beforecellselect', this.customBeforeCellSelect, this);
                }
        });
    
        var sm = new Ext.grid.CellSelectionModel({
            listeners: {
                beforecellselect : {
                    fn: function(selModel, rowIndex, colIndex) {
                        selModel.customBeforeCellSelect.apply(selModel, arguments);
                    },
                    scope: sm
                }
            }
        });
    

    However, keep in mind that you are attaching an event handler to the beforecellselect event in the overridden constructor, so if you call this event handler function again during beforecellselect in the specific instance listeners, then you will end up executing the same function twice in a row.

    For efficiency considerations, you could move the custom handler to the prototype of Ext.grid.CellSelectionModel, i.e., instead of putting customBeforeCellSelect on the individual instance inside init. Do the following to make this possible:

        Ext.grid.CellSelectionModel.prototype.customerBeforeCellSelect =
            function(selModel, rowIndex, colIndex) {
                // etcetera
        };
    

    You would add the above line after your override statement.