Buzut
Buzut

Reputation: 5153

JavaScript Event Listener encapsulated in a function

I have an event listener that is in a function. Both the listener and the emitter are in the same function.

When the event fires, a variable is incremented. So far so good. But when I call the function several times, the listener is triggered several times in the same function call.

var test = function() {    
    var completeStatus = 0;

    $(document).on('gt', function() {
        console.log(++completeStatus);
    });
    $(document).trigger('gt');
}

test();
test();
test();

It expect it to output 1 three times as the function is called three times. But it outputs:

0
1
0
2
1

Why is that and how to obtain the desired behaviour?

Here's a jsfiddle to try it out.

Upvotes: 1

Views: 546

Answers (4)

Buzut
Buzut

Reputation: 5153

An other way would be to generate unique events and handler each time the function is executed:

var test = function() {    
    var completeStatus = 0;
    var uniqid = Math.random().toString(36).slice(-8);

    $(document).on('gt' + uniqid, function() {
        console.log(++completeStatus);
    });
    $(document).trigger('gt' + uniqid);
}

test();
test();
test();

Fiddle

But what about performance implications? Is there any advantage/disadvantage using this approach?

Upvotes: 0

kiran
kiran

Reputation: 384

As mentioned in the above replies .on() adds event listener, so in your example its added 3 times.

In addition to the earlier answer it would be good to avoid adding multiple listeners as it could lead to memory leaks, if you fail to remove them. So you could try this solution which removes the event listeners before adding again.

var test = function() {    
   var completeStatus = 0;
   var GT_EVT = 'gt';

   $(document).off(GT_EVT).on(GT_EVT, function() {
      console.log(++completeStatus);
   });

   $(document).trigger(GT_EVT);

}

Upvotes: 1

Yogendra
Yogendra

Reputation: 2234

Because you are using $(document).trigger('gt'); so it's initiating trigger event in all document event that's why increasing the call of function returning output like

0       //from first function call
1 0     //from second function call 
2 1 0   //frm third function call
.... and so on

Solution :

var test = function() {    
    var completeStatus = 0;
    var pageInitialized = false;    
    $(document).on('gt', function() {
        if(pageInitialized) return;
        console.log(++completeStatus);
        pageInitialized = true;
    });
    $(document).trigger('gt');
}

test();
test();
test();

Upvotes: 2

Oriol
Oriol

Reputation: 288100

.on() adds event listers, it doesn't replace previous ones:

Attach an event handler function for one or more events to the selected elements.

When an element has multiple event listeners, the order is well defined:

Event handlers bound to an element are called in the same order that they were bound.

And .trigger() executes them all in that order:

Execute all handlers and behaviors attached to the matched elements for the given event type.

Therefore,

  1. The first time you call test, you add an event listener with completeStatus = 0, and you trigger it. So you get

    0
    
  2. The second time you call test, the previous event listener has completeStatus = 1. Then you add a second event listener with completeStatus = 0, and you trigger both. So you get

    1 // From the first event listener
    0 // From the second event listener
    
  3. The third time you call test, the first event listener has completeStatus = 2, and the second one has completeStatus = 1. Then you add a third event listener with completeStatus = 0, and you trigger them all. So you get

    2 // From the first event listener
    1 // From the second event listener
    0 // From the third event listener
    

Upvotes: 2

Related Questions