krb686
krb686

Reputation: 1806

Remove an event listener from a component only based off of its function name - Ext Js

Alright so I have a viewport divided into two halves, top and bottom. The top half has combo boxes and input fields that are always visible, the bottom half has a tab panel with multiple tabs.

When I change one of the static combo boxes on the top half, I'll call it combo box A, it fires an event and in its event handler, A_handler, it will attempt to style another combo box in one of the tabs, I'll call it combo box B, but it may do one of two things.

Combo box B is visible on tab 2, not 1.

So then:

1) If tab 1 is active, it will setup an event handler to style combo box B for when tab 2 is made active.

2) Otherwise, it will just immediately style it.

So here's the problem: The initial combo box, A, can style combo box B one of two possible ways, depending on the selection, say red and blue.

So imagine the situation where tab 1 is visible, and I select the option to style B as red, then the event handler is created for when tab 2 is activated. But then, without activating tab 2, I change the option again in combo A, to make box B as blue.

At this point, I need it to remove the first event handler so that only one is fired.

I do not have a reference to the event handlers, but I have named them.

I have created functions to acquire the list of event listeners on tab 2, and know the name of the listener to remove, so I can match names, but the scopes are not the same when I attempt to remove them with the tab's removeListener, so nothing happens.

Upvotes: 0

Views: 3009

Answers (2)

Thevs
Thevs

Reputation: 3251

You may set event handlers to work only once:

someItem.on('event', function() {
    // ... bla bla bla ...
}, scope, {single:true});

Upvotes: 1

krb686
krb686

Reputation: 1806

Solved

Eventually found the solution to this.

The un or removeListener functions are setup like this:

un( eventName, fn, [scope] )

My problem was that I did not have a reference to the specific handler to pass in for fn

The solution involves finding the fn ref by searching with the fn name.

So when the event listener is created, it is setup with a name:

myTab.on('activate', function doSomeStuff() {

Later on when I need to check if it exists/possibly remove it:

objectHasNamedListener: function(obj, eventType, name) {
  var listeners = obj.events[eventType].listeners;

  //trim functionality since .trim() doesn't exist in old IE
  name = name.replace(/^\s+|\s+$/g, '');

  if (listeners != undefined) {
     for (var i = 0; i < listeners.length; i++) {
        var func = listeners[i].fn;
        var funcStr = func.toString();
        var funcName = funcStr.substr('function'.length);
        funcName = funcName.substr(0, funcName.indexOf('('));
        funcName = funcName.replace(/^\s+|\s+$/g, '');
        if (funcName == name) {
           return true;
        }
     }
  }
  return false;
},

And if that returns true, get the reference to that handler:

if (this.objectHasNamedListener(myTab, "activate", "doSomeStuff")) {
    var listener = this.getNamedListener(myTab, "activate", "doSomeStuff");
    myTab.removeListener("activate", listener, this);
}




getNamedListener: function(obj, eventType, name) {
    var listeners = obj.events[eventType].listeners;

    name = name.replace(/^\s+|\s+$/g, '');

    if (listeners != undefined) {
       for (var i = 0; i < listeners.length; i++) {
          var func = listeners[i].fn;
          var funcStr = func.toString();
          var funcName = funcStr.substr('function'.length);
          funcName = funcName.substr(0, funcName.indexOf('('));
          funcName = funcName.replace(/^\s+|\s+$/g, '');

          if (funcName == name) {
             return func;
          }
       }
    }

    return null;

 },

The other caveat is that the listener had to be created and removed with the same scope passed in, despite the fact that it is listed as [optional] in the API, so passing in this worked fine

Upvotes: 0

Related Questions