Getting what the current class is declared as - javascript

I am writing a class which manipulates some innerHTML & onclick tags of a div, which puts some function in it that is calls something within the class, however, as there are going to be more than one use of the class on a single page.
I was wondering if it was possible within the class to workout what that particular object had been labelled?
function Bob() {
this.test = function()
{
alert('test');
}
this.Bob = function()
{
element.onClick = function() {(some piece of code).test();};
element.innerHTML = "Test";
}
}

function Bob() {}
Bob.prototype.test = function () {
/* do things */
};
Bob.prototype.Bob = function () {
element.addEventListener("click", function () {
this.test();
}.bind(this));
toArray(element.childNodes).forEach(function (node) {
element.removeChild(node);
});
var button = document.create("button");
button.classList.add("button-style");
element.appendChild(button);
button.addEventListener("click", function () {
this.test();
}.bind(this));
};
You want to use .bind to bind functions to a `thisContext

function Bob() {
var self = this;
this.test = function()
{
alert('This is the Bob class');
}
element.onClick = function() {
self.test();
};
}
Due to how closures work the "self" variable will still be inscope within that element's onclick even after the Bob constructor returns.
Simply have different classes return different alert messages inside the test function

Related

Cannot removeEventListener HTML5 Canvas [duplicate]

In JavaScript, what is the best way to remove a function added as an event listener using bind()?
Example
(function(){
// constructor
MyClass = function() {
this.myButton = document.getElementById("myButtonID");
this.myButton.addEventListener("click", this.clickListener.bind(this));
};
MyClass.prototype.clickListener = function(event) {
console.log(this); // must be MyClass
};
// public method
MyClass.prototype.disableButton = function() {
this.myButton.removeEventListener("click", ___________);
};
})();
The only way I can think of is to keep track of every listener added with bind.
Above example with this method:
(function(){
// constructor
MyClass = function() {
this.myButton = document.getElementById("myButtonID");
this.clickListenerBind = this.clickListener.bind(this);
this.myButton.addEventListener("click", this.clickListenerBind);
};
MyClass.prototype.clickListener = function(event) {
console.log(this); // must be MyClass
};
// public method
MyClass.prototype.disableButton = function() {
this.myButton.removeEventListener("click", this.clickListenerBind);
};
})();
Are there any better ways to do this?
Although what #machineghost said was true, that events are added and removed the same way, the missing part of the equation was this:
A new function reference is created after .bind() is called.
See Does bind() change the function reference? | How to set permanently?
So, to add or remove it, assign the reference to a variable:
var x = this.myListener.bind(this);
Toolbox.addListener(window, 'scroll', x);
Toolbox.removeListener(window, 'scroll', x);
This works as expected for me.
For those who have this problem while registering/removing listener of React component to/from Flux store, add the lines below to the constructor of your component:
class App extends React.Component {
constructor(props){
super(props);
// it's a trick! needed in order to overcome the remove event listener
this.onChange = this.onChange.bind(this);
}
// then as regular...
componentDidMount (){
AppStore.addChangeListener(this.onChange);
}
componentWillUnmount (){
AppStore.removeChangeListener(this.onChange);
}
onChange () {
let state = AppStore.getState();
this.setState(state);
}
render() {
// ...
}
}
It doesn't matter whether you use a bound function or not; you remove it the same way as any other event handler. If your issue is that the bound version is its own unique function, you can either keep track of the bound versions, or use the removeEventListener signature that doesn't take a specific handler (although of course that will remove other event handlers of the same type).
(As a side note, addEventListener doesn't work in all browsers; you really should use a library like jQuery to do your event hook-ups in a cross-browser way for you. Also, jQuery has the concept of namespaced events, which allow you to bind to "click.foo"; when you want to remove the event you can tell jQuery "remove all foo events" without having to know the specific handler or removing other handlers.)
jQuery solution:
let object = new ClassName();
let $elem = $('selector');
$elem.on('click', $.proxy(object.method, object));
$elem.off('click', $.proxy(object.method, object));
We had this problem with a library we could not change. Office Fabric UI, which meant we could not change the way event handlers were added. The way we solved it was to overwrite the addEventListener on the EventTarget prototype.
This will add a new function on objects element.removeAllEventListers("click")
(original post: Remove Click handler from fabric dialog overlay)
<script>
(function () {
"use strict";
var f = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function (type, fn, capture) {
this.f = f;
this._eventHandlers = this._eventHandlers || {};
this._eventHandlers[type] = this._eventHandlers[type] || [];
this._eventHandlers[type].push([fn, capture]);
this.f(type, fn, capture);
}
EventTarget.prototype.removeAllEventListeners = function (type) {
this._eventHandlers = this._eventHandlers || {};
if (type in this._eventHandlers) {
var eventHandlers = this._eventHandlers[type];
for (var i = eventHandlers.length; i--;) {
var handler = eventHandlers[i];
this.removeEventListener(type, handler[0], handler[1]);
}
}
}
EventTarget.prototype.getAllEventListeners = function (type) {
this._eventHandlers = this._eventHandlers || {};
this._eventHandlers[type] = this._eventHandlers[type] || [];
return this._eventHandlers[type];
}
})();
</script>
Here is the solution:
var o = {
list: [1, 2, 3, 4],
add: function () {
var b = document.getElementsByTagName('body')[0];
b.addEventListener('click', this._onClick());
},
remove: function () {
var b = document.getElementsByTagName('body')[0];
b.removeEventListener('click', this._onClick());
},
_onClick: function () {
this.clickFn = this.clickFn || this._showLog.bind(this);
return this.clickFn;
},
_showLog: function (e) {
console.log('click', this.list, e);
}
};
// Example to test the solution
o.add();
setTimeout(function () {
console.log('setTimeout');
o.remove();
}, 5000);
As others have said, bind creates a new function instance and thus the event listener cannot be removed unless it is recorded in some way.
For a more beautiful code style, you can make the method function a lazy getter so that it's automatically replaced with the bound version when accessed for the first time:
class MyClass {
activate() {
window.addEventListener('click', this.onClick);
}
deactivate() {
window.removeEventListener('click', this.onClick);
}
get onClick() {
const func = (event) => {
console.log('click', event, this);
};
Object.defineProperty(this, 'onClick', {value: func});
return func;
}
}
If ES6 arrow function is not supported, use const func = (function(event){...}).bind(this) instead of const func = (event) => {...}.
Raichman Sergey's approach is also good, especially for classes. The advantage of this approach is that it's more self-complete and has no separated code other where. It also works for an object which doesn't have a constructor or initiator.
If you want to use 'onclick', as suggested above, you could try this:
(function(){
var singleton = {};
singleton = new function() {
this.myButton = document.getElementById("myButtonID");
this.myButton.onclick = function() {
singleton.clickListener();
};
}
singleton.clickListener = function() {
console.log(this); // I also know who I am
};
// public function
singleton.disableButton = function() {
this.myButton.onclick = "";
};
})();
I hope it helps.
can use about ES7:
class App extends React.Component {
constructor(props){
super(props);
}
componentDidMount (){
AppStore.addChangeListener(this.onChange);
}
componentWillUnmount (){
AppStore.removeChangeListener(this.onChange);
}
onChange = () => {
let state = AppStore.getState();
this.setState(state);
}
render() {
// ...
}
}
It's been awhile but MDN has a super explanation on this. That helped me more than the stuff here.
MDN :: EventTarget.addEventListener - The value of "this" within the handler
It gives a great alternative to the handleEvent function.
This is an example with and without bind:
var Something = function(element) {
this.name = 'Something Good';
this.onclick1 = function(event) {
console.log(this.name); // undefined, as this is the element
};
this.onclick2 = function(event) {
console.log(this.name); // 'Something Good', as this is the binded Something object
};
element.addEventListener('click', this.onclick1, false);
element.addEventListener('click', this.onclick2.bind(this), false); // Trick
}
A problem in the example above is that you cannot remove the listener with bind. Another solution is using a special function called handleEvent to catch any events:

object oriented javascript - this [function] is not a function

I am moving some jquery functions into a javascript object to clean up some code. My problem is, when I put methods on my object's constructor, calling this.functionName() returns the error this.functionName is not a function but if my functions are helper methods and are outside of the object's constructor, they work just fine.
Here is my code that does not work
function MyConstructor() {
this.init();
this.selectAllHandler();
}
MyConstructor.prototype = {
init: function() {
var self = this;
$(document).on('click', '#my_element', function() {
self.selectAllHandler.call(this);
});
},
selectAllHandler: function() {
// handler works fine
var ids_array = this.idsArray(checkboxes); // error happening here
},
// helpers
idsArray: function(checkboxes) {
// trying to call
}
}
But, having my object w/ a constructor and then calling the "helper" outside of the object works fine. For example, this works fine.
function MyConstructor() {
this.init();
}
MyConstructor.prototype = {
init: function() {
var self = this;
$(document).on('click', '#my_element', function() {
self.selectAllHandler.call(this);
});
},
selectAllHandler: function() {
// handler works fine
var ids_array = idsArray(checkboxes);
}
}
function idsArray() {
// code that works fine
}
One thing to note as well, is that in this scenario, by running console.log this refers to the element being clicked on, and not the constructor.
I have tried using call, apply, and bind, but have not had success, though I think it's been syntax related.
How can I build this so I can call my "helper" functions inside my object?
Not sure how you were using bind, since you said it didn't work for you.
If you want, you can use bind like below. Also, in your code snippet checkboxes was not defined. This way you don't need to use self.
function MyConstructor() {
this.init();
this.selectAllHandler();
}
MyConstructor.prototype = {
init: function() {
//var self = this;
$(document).on('click', '#my_element', function() {
//self.selectAllHandler.call(self);
this.selectAllHandler();
}.bind(this));
},
selectAllHandler: function() {
// handler works fine
var checkboxes;
var ids_array = this.idsArray(checkboxes); // error happening here
},
// helpers
idsArray: function(checkboxes) {
// trying to call
console.log('test');
}
}
var o = new MyConstructor();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I was able to figure it out. I thought I could call another function in the constructor just using this.functionName(). however, $(this) was referring to the element I was clicking on.
I remembered I defined self (this) in my init function which refers to the window object. Well, inside the window object is my object, and my function is on that object. So i was able to successfully call my object by doing
function MyConstructor() {
this.init();
}
MyConstructor.prototype = {
init: function() {
var self = this;
$(document).on('click', '#my_element', function() {
self.selectAllHandler.call(this);
});
},
selectAllHandler: function() {
// RIGHT HERE
var ids_array = self.MyConstructor.prototype.idsArray(checkboxes);
},
// helpers
idsArray: function(checkboxes) {
// some codes
}
}

How to register an onclick event so it knows the object it is called from?

I have some simple HTML & Javascript code:
<span id="test">Hej</span>
function Hello(el)
{
var el = document.getElementById('test');
this.test = function(fun)
{
el.addEventListener('click', function(e)
{
fun(e);
}, false);
}
}
var hello = new Hello;
hello.test(function()
{
console.log(this);
});
I would like to use "this" in console.log() but I want it to refer to the instance of hello.
How should I change the definition of Hello?
You can use Function#call, which lets you bind this to whatever you want:
function Hello(el)
{
var el = document.getElementById('test');
var that = this;
this.test = function(fun)
{
el.addEventListener('click', function(e)
{
fun.call(that, e);
}, false);
}
}
See this jsfiddle.
In your this.test function replace:
fun(e);
With:
fun.call(that, e);
And add the following before your event listener:
var that = this;
You need to pass it to the passed function. The method addEventListener already provides you with access to the calling element through the usage of the this keyword in the specified listener function. So in order for this object to make it to your "fun" function, it needs to be passed as a variable.
function Hello(el)
{
var el = document.getElementById('test');
this.test = function(fun)
{
el.addEventListener('click', function(e)
{
fun(e, this); // Adding the parameters to pass
}, false);
}
}
var hello = new Hello();
hello.test(function(event, el) // The passed function should be ready to receive it
{
alert(el.innerText);
});
I tested it with this fiddle.
Edit: Not sure I read the question fully the first time, but if you want to have access to Hello from within the function, you'll need to provide an instance of it from within your "class definition".
function Hello(el)
{
var self = this;
var el = document.getElementById('test');
this.test = function(fun)
{
el.addEventListener('click', function(e)
{
fun(e, self); // Adding the parameters to pass
}, false);
}
this.someProperty = "to test the value";
}
var hello = new Hello();
hello.test(function(event, obj) // The passed function should be ready to receive it
{
alert(obj.someProperty);
});
I tested this second version with this fiddle update.

anonymous event handler doesn't have access to prototype method

Can't access fx1 from fx2 inside an anonymous function handler?
var MyComponent = function () {
//my constructor
}
MyComponent.prototype.fx1 = function() { //code }
MyComponent.prototype.fx2 = function() {
var btn1 = document.getElementById('Button1')
btn1.onclick = function() {
//issue is here
//trying to call fx1 from here but can't access it.
this.fx1(); //doesn't work.
}
}
As this is bound to the button within the onclick handler, you cannot use it to access the MyComponent instance. But you can simply save the reference in another variable which you then can use:
MyComponent.prototype.fx2 = function() {
// save reference to the instance
var self = this;
var btn1 = document.getElementById('Button1')
btn1.onclick = function() {
// access the saved reference to the MyComponent instance
self.fx1();
}
}
Another way to do this:
MyComponent.prototype.fx2 = function() {
var btn1 = document.getElementById('Button1');
btn1.onclick = (function() {
this.fx1();
}).bind(this);
}

JavaScript: call of function with 'this.' does not reference to method in class

Here is an abstract JavaScript code sample that illustrates the situation that is causing me to ask a question here:
function className (){
var private_variable = 0;
function privateMethod(){
// Some irrelevant code.
};
this.privilegedMethod = function (){
// Some relevant code to determine if private variable needs to be modified.
private_variable+=val; // Modifies private variable.
};
this.init = function () {
$(window).keydown(function (key) {
if (key.which == 13) {
privateMethod(); // Call to private method works fine.
this.privilegedMethod(); // 'this' references Window object,
// not this class method as expected.
}
});
};
};
My question is - is there an alternative way I can make call this.privilegedMethod() reference to it's class, not the Window object which it is applied to?
Or perhaps any suggestions how I could restructure my code keeping the functionality -- key events are listened globally, the method of modifying the private variable is accessible outside the class, but private variable itself is not.
P.S. Placing the call to the privileged method inside the private did not change anything.
this.init = function () {
var that = this;
$(window).keydown(function (key) {
if (key.which == 13) {
privateMethod();
that.privilegedMethod();
}
});
};
or
this.init = function () {
$(window).keydown($.proxy(function (key) {
if (key.which == 13) {
privateMethod();
this.privilegedMethod();
}
}, this));
};
The deal is that inside the keydown handler the scope is the window object, so the "this" keyword refers to the window which does not have you method.
James solution should work fine.
function className (){
var private_variable = 0;
function privateMethod(){
// Some irrelevant code.
};
this.privilegedMethod = function (){
// Some relevant code to determine if private variable needs to be modified.
private_variable+=val; // Modifies private variable.
};
this.init = function () {
var handle = $.proxy(this.privilegedMethod, this);
$(window).keydown(function (key) {
if (key.which == 13) {
privateMethod();
handle();
}
});
};
};
http://api.jquery.com/jQuery.proxy/

Categories

Resources