CreateJS createjs.Ticker.off("tick", element.update) not working - javascript

I'm making a shooting game in which I need to update the state of bullets by binding them to the 'tick' event, however when calling the remove method to remove them from the 'tick' event it does not removes it. After creating a new instance this keeps getting updated instead of the one that was binded.
The methods 'add'/'remove' are used to bind/unbind the methods from the 'tick' event
class window.Stage
stage = undefined
counter = 0
fps = 60
add: (element) =>
element.id = counter++
stage.addChildAt(element.view, element.id)
element.listener = createjs.Ticker.on("tick", element.update)
remove: (element) =>
createjs.Ticker.off("tick", element.listener) # Not removing!
stage.removeChildAt(element.id)
update: () =>
stage.update()
This is how I'm calling the remove method in the Game class
run: () =>
if #gun? && !#gun.alive
#stage.remove(#gun)
#gun = undefined
if #player.shooting() && !#gun?
#gun = #player.shoot() # Ticker keeps updating new instance
#stage.add(#gun)
for bunker in #bunkers
if #gun? && bunker.gotShot(#gun)
#gun.alive = false
This is how bullets are created
class window.Player
shoot: =>
new Gun(#name, #x, #y - radius, false)
If there's any tutorial to better undestand how to correctly use listerners a link will be very much appreciated, thanks is advance.

The off() method requires you pass the method closure generated by calling on(), and not the original method that is passed. This is because the on() method generates a closure to maintain scope -- whereas addEventListener will not scope methods for you, requiring you to bind them yourself, or use global or anonymous handlers.
Make sure to store off the closure, and pass that instead. I am not familiar with the syntax in your example, so here is a vanilla JS example:
var listener = element.on("tick", handler, this);
element.off("tick", listener);
Note that the 3rd parameter is the scope the method should be called in, and if you don't pass it, it still generates a closure, and fires it in the element's scope instead of anonymously. There are also some other nice features of the on() approach, such as the "fire once" and event.remove() functionality.
You can always stick with the addEventListener/removeEventListener methods if you would prefer the same behaviour as DOM level 3 events.

Related

How to pass an Event Object into a nested function?

How do I pass an event object into a nested function and have it be understood by the script?
Below is not my actual code but it illustrates the issue. The function there cannot complete, because evt.target.src is out of scope, I guess. Again, this is dumbed down code. I'm only asking how can the evt.target.src be understood from inside this nested function.
SomeFunction =(evt)=> {
setTimeout(
()=> {evt.target.src = somethingIcreated}, 200
)
};
If I assign it to a variable outside of the nested function to pass in, it's just understood as some random variable, not the actual event object's src. Thus the src won't change or the project will crash because it cannot work with something that is null.
React uses synthetic events and it reuses them, so you're not allowed to use them after the handler returns.
You have two choices:
You can grab properties from them and them later. So in your case:
SomeFunction = ({target}) => {
setTimeout(
()=> {target.src = somethingIcreated}, 200
)
};
There, I'm using destructuring in the parameter list to grab the target property from the event object, which it's okay to reuse later. It's just the event object itself that you can't use after the handler returns.
You can use the persist method on the event to tell React you want to keep it.
More in the synthetic events documentation.

Removing event handlers in the destroy method of vanilla JavaScript plugins

What's the best way of unbinding event handlers in the destroy method of a plain JS plugin? The following (non working) code shall demonstrate what I mean:
var myPlugin = (function(){
function myPlugin(selector){
var elems = document.querySelectorAll(selector);
for (var i=0; i<elems.length; i++) {
function _handler(){ console.log('Hello'); }
elems[i].addEventListener("click", _handler);
}
this.destroy = function(){
document.removeEventListener("click", _handler);
};
}
return myPlugin;
})();
So, I iterate over a set of elements and do something with them, including attaching an event handler function. The problem: In plain JS, I need a reference to the original handler in order to remove it when the plugin instance gets destroyed.
This snippet naturally cannot work, because the event handler function is written over and over again with each selected element.
One way of handling this: Creating functions with a dynamic/unique name, as described here: Creating functions dynamically in JS.
The function needs to be globally set on the window object. Then, I just need to remember the name (e.g. by using a data attribute on the selected element) and with that, it's possible to unbind the event later on.
However, this approach is clumsy and I run into issues on IE8, when using such function with attachEvent. Is there a better way or any best practice for that?

How to implement OnDestroy/OnDispose event in JS/Mootools?

Is there any existing OnDestroy/OnDispose event in JavaScript or are there any known custom implementations in plain JS or Mootools? Let's say I want to call console.log('bye') when an element gets destroyed/removed from the DOM. Something similar to this jQuery solution
whereas you can do this, it's not practical to do so.
first - destroy - the event fill fire with the context of the element that is being destroyed, at which point during the event cb, it will get removed and GCd, potentially.
second, IE6,7,8 where Element prototype is read-only and elements get the methods added to them locally via the $/document.id - means that the decorated methods need to be loaded before anything is accessed in the DOM.
third, this won't actually fire if say, el.parentNode.innerHTML = '' or they get removed via raw js / alternative ways. it's not a true watcher in that sense, just traps 2 methods.
http://jsfiddle.net/5YYyb/1/
(function(){
// old methods
var destroy = Element.prototype.destroy,
dispose = Element.prototype.dispose;
// redefine them and fire the events before calling old protos.
[Element, Elements].invoke('implement', {
destroy: function(){
this.fireEvent('destroy');
return destroy.apply(this, arguments);
},
dispose: function(){
this.fireEvent('dispose');
return dispose.apply(this, arguments);
}
});
}());
var foo = document.getElement('.foo');
foo.addEvents({
dispose: function(){
alert('we are not in the dom now');
}
});
foo.dispose();

Bind and unbind a bound function to an event

I am using EventEmitter2 as message bus internal within my application. Now I need to bind and unbind some event handlers. As I want them also to bind them to a given context, I end up with the following syntax:
messageBus.on('foo::bar', _.bind(eventHandler, this));
The problem is that I need to unbind them at a later point in time, so I wrote:
messageBus.off('foo::bar', _.bind(eventHandler, this));
Unfortunately this does not work, as _.bind each time returns a new instance of the wrapper function. Now of course I could run _.bind once and bind the wrapped function, such as this:
var fn = _.bind(eventHandler, this);
messageBus.on('foo::bar', fn);
messageBus.off('foo::bar', fn);
This works perfectly well, but if you have a few event handlers, the code quickly starts to get less readable than necessary.
How might you solve this without the need to externalize the call to the bind function? Is there an alternative function that always returns the same wrapper in case you call it multiple times and the function as well as the context are the same?
Underscore.js provides a bindAll method just for this use-case, from the documentation:
Binds a number of methods on the object, specified by methodNames, to be run in the context of that object whenever they are invoked
Failing that, you could make use of a closure which always returns the same bound function when invoked, ie:
function getOrCreateBoundEventHandlerFor(eventType, callback) {
// Initialise the handler map if it's not already been created.
this._boundEventHandlerMap = this._boundEventHandlerMap || {};
// If no handler was mapped, create a new one.
if (this._boundEventHandlerMap[eventType] === void 0) {
this._boundEventHandlerMap[eventType] = _.bind(callback, this);
}
return this._boundEventHandlerMap[eventType];
}

Javascript Object Inheritence

I'm creating a control for Google maps v2. While creating my control I've found a design challenge and want to find an appropriate solution. Here's the goods.
A custom Google control inherits from GControl;
myControl.prototype = new GControl();
Next I need to overload the initializer so here it is.
myControl.prototype.initilize = function (map) {
//do some work and return stuff
};
Now within my custom controls initlize function I create a couple elements which, using the GEvent class, I subscribe to various events. To make my callback functions managable, I included them into the controls prototype.
myControl.prototype.onEvent = function(e){
//do some work;
//modify the members of the current myControl instance
};
Within my callback function "onEvent" I want to modify members within my control. What is the best way to access my control from the function? The keyword "this" cannot be used because that is a reference to the element that was clicked, in my case a div. And I can't access the members through the prototype because I need a specific instance of the object. The only viable solution I've considered is to create my control globally in one of my scripts. Is this the best method?
The easiest thing that I can think, it to define your onEvent method within your constructor, there you will have quick access to the current object instance, and you will not have to modify your public API:
function MyControl () {
var instance = this; // store a reference to 'this'
this.onEvent = function (e) {
// use the instance variable
instance.otherMethod();
};
}
Note that in this approach, the onEvent property will exist physically in your object instances (obj.hasOwnProperty('onEvent') = true).
Edit: You can simply use the GEvent.bind function:
GEvent.bind(map, "click", myObj, myObj.onEvent);
The above bind method will enforce the context, so the this keyword inside myObj.onEvent will point to the myObj object instance when the event is triggered, it will work with your code without problems.
I'm not familiar with how you subscribe to events using GEvent, so I'll make that part up. Do this:
myControl.prototype.onEvent = function(e, instance) {
// do some work
// modify members of 'instance'
};
function wrap(handler, instance) {
return function(e) {
handler(e, instance);
}
}
GEvent.Register('Event', wrap(instance.onEvent, instance));

Categories

Resources