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?
Related
There are several elements on HTML page which triggers a js function HardCoded().
I cannot modify HardCoded() function.
I want to run some custom js code after the HardCoded() function is getting called. How can I do that? Is there any handlers for js functions?
I'm building a chrome extension that's why I cannot modify page source code.
I have access to JQuery.
One way is to find all elements who are calling HardCoded() and attach events to those elements but I would like to avoid this method.
You could do something like this:
var oldFn = HardCoded;
window.HardCoded = function(){
var res = oldFn.apply(this, arguments);
// New Code ....
return res;
}
What this does is to create a reference to the HardCoded function, redefine this function and then call the old implementation using the previously created reference.
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();
Let's imagine that we have a code like this:
function someName(callback) {
var elem = document.createElement('input');
elem.addEventListener('change', function(evt) {
callback();
}, false);
// some code
elem.click();
}
// some code
someName(function() {
alert("Hello world!");
});
The question is: will JS completely remove the "elem" element created in the "someName" function after moving out of it's callback's context? The other question is: will JS remove the "elem" element if it is not changed after emitting the "click" event?
Can you, please, explain me when the "elem" element will be removed?
P.S.: I'm trying to write a simple application with node-webkit and such kind of code is needed to let node-webkit open a file dialog (open file, save file and so on) and handle it's result.
Variables defined inside a function only exist inside the function when the function is executed.
Your code creates an input element and it assigns a callback function to it's state change handler, but you don't actually attach/insert the element to the DOM anywhere, so the element only exists as that variable; it never becomes something in the DOM to exist after the function ends
Therefore when the function ends, the variable will be destroyed and that element wouldn't exist anymore, including the state change handler.
sidenote: it's .createElement() not .create() (unless you have code that defined a .create() method..)
I'm working on a Single Page App and quite a few of the DOM node construction functions return a reference to the object they've created. Here's an example of what I mean:
if (!document.getElementById('playlistHeader')) {
appView.buildKit.playlist.headerWrap();
}
// construct element
var secondaryBtnsWrap = document.createElement("div");
secondaryBtnsWrap.id = "playlistSecondaryBtnWrap";
secondaryBtnsWrap.className = "clearright right";
// attach it
document.getElementById('playlistHeader').appendChild(secondaryBtnsWrap);
// return reference to dom node
return secondaryBtnsWrap;
I figured it would be redundant to destroy and recreate the node when changing between views, so I started working towards being able to wipe the content of some nodes (subsections of the site) by giving them a custom function that handles the wiping.
// build wipe function
secondaryBtnsWrap.wipe = function(){
// do custom wiping here
}
The idea is to "reset" parts of the UI and rebuild the differences between the views. For example, if there was a button that we'd need regardless, the wipe function won't delete it. That way it eliminates the extra legwork of creating the same element.
In some cases it's a lot easier to get a reference to a node and trigger the custom function attached, but I was wondering if its actually a good idea or if it just SEEMS like a good idea (but isn't).
TL;DR VERSION
Is it a good idea to give DOM nodes Javascript functions?
DOM Nodes are first-class objects. Nothing wrong with assigning them your own properties. Just don't try to overwrite any built-ins (except perhaps event handlers, but you should really be using attachEvent/addEventListener). In my opinion, it's one of the most convenient features of javascript in terms of user-interface development.
You could also build your page with a standard object which generates its own DOM nodes. You can attach event listeners which invoke functions on said object for interactivity. Use closures to reference the owner object. For instance:
function Foo() {
this.element = undefined;
this.createTextbox();
}
Foo.prototype.createTextbox = function() {
var $self = this;
this.element = document.createElement('input');
this.element.type = 'text';
this.element.addEventListener('change', function() {
$self.onChange.apply($self, arguments);
});
}
Foo.prototype.onChange = function() {
console.log(this.element.value);
}
Foo.prototype.Render = function(target) {
target = target || document.body;
target.appendChild(this.element);
}
var foo = new Foo();
foo.Render();
Both methods are equally valid, but I'd say the latter is probably more convenient when either the design or functionality needs to be significantly modified (rather than changing ids, classes, and layouts in both places, you only have to change them in one).
Say, I have two HTML elements - an input field and a button.
The code for both is generated programatically.
After I generate the code, I have a function that binds event handlers to those elements.
//Locate add to order button and bind event handler to it
this.input_add = document.getElementById("add_to_order");
this.input_add.onclick =
function () {
return controller.addToOrder.call(controller);
};
// Locate quantity input and bind event handler to it
this.input_quantity = document.getElementById("form_quantity");
this.input_quantity.onkeyup =
function () {
return controller.changeQuantity.call(controller, this);
};
Here's the puzzle - controller.changeQuantity requires a reference to this.input_add.
As far as I can tell, I can't pass this.input_add into the call parameter list for controller.changeQuantity.
I've found only one solution - putting a reference to this.input_add in the this.input_quantity object.
this.input_quantity.addButton = this.input_add
Are there any alternatives? Is this a good practice? I'm trying to keep my application as decoupled as possible.
Add your DOM objects to your "controller", and set up your event handlers as part of that object, something like:
var controller = { ... };
controller.input_add = document.getElementById("add_to_order");
controller.input_quantity = document.getElementById("form_quantity");
controller.input_add.onclick = function() { controller.addToOrder.call(controller, this);}
Then you can reference these DOM elements from within your controller object at any point.
I often set up references to DOM elements, register event handlers, etc. in the setup code for my main Javascript controller object.