Skip to main content
Inspiring
December 29, 2016
Answered

Canvas removeEventListener doesn't work for tick

  • December 29, 2016
  • 2 replies
  • 3660 views

this.addEventListener('tick', load.bind(this));

var i = 0;

function load(){

  this.removeEventListener('tick', load); // doesn't wok

  console.log(i++); // always here

}

also tried to do

this.removeEventListener('tick', load.bind(this));
This topic has been closed for replies.
Correct answer ClayUUID

A more correct thread title would be "Canvas removeEventListener doesn't work for bind".

Your problem is that removeEventListener() requires the same function reference as passed to addEventListener() to succeed in removing the listener. But bind() returns a different function reference every time it's used. That's why your code doesn't work. Of course, the reason bind() is needed at all is because by default event handlers execute in the browser window (global) context instead of the context of the object that triggered it.

There are two ways to work around this:

First way, store a global reference to your "this" so the function can access it.

loadThis = this; // global

this.addEventListener("tick", load);

var i = 100;

function load() {

    loadThis.removeEventListener("tick", load);

    console.log(this);

    console.log(i);

}

Second way, store a reference to the bound event handler function so it can be removed.

var loadHandler = load.bind(this); // bound event handler

this.addEventListener("tick", loadHandler);

var i = 100;

function load() {

    this.removeEventListener("tick", loadHandler);

    console.log(this);

    console.log(i);

}

At this point you should be wondering how both versions are able to access the value of i even though they execute in different contexts. That's because, while the first example executes in window context, the function still has access to local scope. Context is the current value of "this", while scope is how JavaScript resolves variables. JavaScript uses lexical (aka "static") scoping, so a function always has access to its parent, etc. variables no matter what context it's executing in.

This article does a far more thorough job explaining all this:

Understanding Scope and Context in JavaScript | Ryan Morr

2 replies

ClayUUIDCorrect answer
Legend
December 29, 2016

A more correct thread title would be "Canvas removeEventListener doesn't work for bind".

Your problem is that removeEventListener() requires the same function reference as passed to addEventListener() to succeed in removing the listener. But bind() returns a different function reference every time it's used. That's why your code doesn't work. Of course, the reason bind() is needed at all is because by default event handlers execute in the browser window (global) context instead of the context of the object that triggered it.

There are two ways to work around this:

First way, store a global reference to your "this" so the function can access it.

loadThis = this; // global

this.addEventListener("tick", load);

var i = 100;

function load() {

    loadThis.removeEventListener("tick", load);

    console.log(this);

    console.log(i);

}

Second way, store a reference to the bound event handler function so it can be removed.

var loadHandler = load.bind(this); // bound event handler

this.addEventListener("tick", loadHandler);

var i = 100;

function load() {

    this.removeEventListener("tick", loadHandler);

    console.log(this);

    console.log(i);

}

At this point you should be wondering how both versions are able to access the value of i even though they execute in different contexts. That's because, while the first example executes in window context, the function still has access to local scope. Context is the current value of "this", while scope is how JavaScript resolves variables. JavaScript uses lexical (aka "static") scoping, so a function always has access to its parent, etc. variables no matter what context it's executing in.

This article does a far more thorough job explaining all this:

Understanding Scope and Context in JavaScript | Ryan Morr

Legend
December 30, 2016

Also, if you only want an event handler to execute once, there are a couple of easier ways to do it.

Using the on method to assign your event listener allows passing a flag that specifies it only fires once:

this.on("tick", load, this, true);

var i = 100;

function load() {

    console.log(this);

    console.log(i);

}

Or you can use the event object remove() method in the handler:

this.addEventListener("tick", load);

var i = 100;

function load(evt) {

    evt.remove();

    console.log(this);

    console.log(i);

}

Participating Frequently
May 11, 2020

this post is too old and not sure if i am getting any answers on my questions. but any help will appreciate.

I am new in Adobe animate CC  and using canvas Html5.
want to remove my first event which called earlier and want to call another event. Below is my code.

 

this.button1.addEventListener("click", fl_popup_down.bind(this))

function fl_popup_down() {
this.popup_window.gotoAndPlay(2);
this.popup_window.button2.addEventListener("click", fl_popup_up.bind(this));
this.button1.removeEventListener("click", fl_popup_down.bind(this)) //not working
alert ('clicked1');

}

function fl_popup_up() {
this.popup_window.gotoAndPlay(11);
alert ('clicked2');
}

kglad
Community Expert
Community Expert
December 29, 2016

use:

var tl=this;

tl.addEventListener('tick', load.bind(this));

var i = 0;

function load(){

tl.removeEventListener('tick', load); // doesn't wok

console.log(i++); // always here

}