How to Bind Event with OOP JS [duplicate] - javascript

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 4 years ago.
I need to bind a Blur event into a Method with JS, and retrieve the object data. That's what I got:
class TestClass {
constructor(input) {
this.inputTest = input;
this.objectTest = {
1: "one",
2: "two",
3: "three"
}
this.isBinded = false;
}
test() {
if(!this.isBinded) {
this.inputTest.addEventListener("blur", function( event ) {
alert("Test Event");
// I need to access to Object Scope, but seems not to be working
console.log(this.objectTest);
});
}
this.isBinded = true;
}
}
var test = new TestClass(document.querySelector("input"));
test.test();
So, this is a simple example of what I need. I have one input, and when I initialize the class, I bind a blur event. When I try it, it just shows me the alert, so apparently looks to work.
However, it seems it cannot access into the object scope, because it doesn't return me the this.objectTest object example from the object scope.
Can anyone help me? Thanks

Because you're using a regular function in the addEventListener it is rebinding this to the inputTest element. You need to use an arrow function to keep this as your class object. Like this:
this.inputTest.addEventListener("blur", ( event ) => {
alert("Test Event");
// I need to access to Object Scope, but seems not to be working
console.log(this.objectTest);
});

However, it seems it cannot access into the object scope, because it doesn't return me the this.objectTest object example from the object scope
Yes, indeed inside the addEventListener callback, this refers to the input that you are attaching the event to, so this.objectTest will be undefined, as it's not referring your class's objectTest property.
What you need to do is to make a reference to your class this, so you can access it inside the callback, you can assign it to another variable like this:
test() {
var _self = this;
if(!this.isBinded) {
this.inputTest.addEventListener("blur", function( event ) {
alert("Test Event");
// I need to access to Object Scope, but seems not to be working
console.log(_self.objectTest);
});
}
this.isBinded = true;
}
Demo:
Here's a Demo showing how it works.
class TestClass {
constructor(input) {
this.inputTest = input;
this.objectTest = {
1: "one",
2: "two",
3: "three"
}
this.isBinded = false;
}
test() {
var _self = this;
if (!this.isBinded) {
this.inputTest.addEventListener("blur", function(event) {
alert("Test Event");
// I need to access to Object Scope, but seems not to be working
console.log(_self.objectTest);
});
}
this.isBinded = true;
}
}
var test = new TestClass(document.getElementById("js-test"));
test.test();
Check it : <input id="js-test" />

Related

What is happening when using the keyword this in lambdas vs functions with Typescript [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
I am using Typescript for an Angular 2 project. I notice that when we use the keyword this inside a labmda expression vs a function, this refers to different things.
For example, let's say I have an Angular component like the following.
export class MyComponet {
isActive = true;
names = [ "john", "jeff", "jared" ];
doSomethingWithLambda() {
names.forEach( (value, index) => {
if(this.isActive) { //this.isActive refers to MyComponent.isActive
//do something...
}
});
}
doSomethingWithFunction() {
names.forEach( function(value, index) {
if(this.isActive) { //this.isActive is undefined, since this refers to the function
//do something
}
});
}
doSomethingWithFunction2() {
let isActive = this.isActive;
names.forEach( function(value, index) {
if(isActive) { //if we change isActive will this also change MyComponent.isActive?
//do something
}
});
}
}
What is really happening here (behind the scene, so to speak)? What's the magic behind this inside a lambda that makes it able to "correctly" refer to the outer class' fields? I understand this inside a function will refer to the function itself.
Also, I have a doSomethingWithFunction2 method that will reference MyComponent.isActive into a local variable. If I change that local variable, that should be like changing the one it references, right? (regardless of it being a "primitive" like integer/number or an "object" like JSON { })
The fat-arrow function syntax is shorthand for:
function () { }.bind(this);
bind is a Javascript ES5 method equivalent to this:
Function.prototype.bind = function bind(context) {
var func = this;
return function () {
return func.apply(context, arguments);
};
}
In regards to
Also, I have a doSomethingWithFunction2 method that will reference MyComponent.isActive into a local variable. If I change that local variable, that should be like changing the one it references, right? (regardless of it being a "primitive" like integer/number or an "object" like JSON { })
In Javascript, variables are like pointers and except for some limited cases (primitives and copy-on-write objects) will change the referenced value when mutated. Reassigning will not change the original value, e.g. isActive = false; but this.isActive = false would in fact re-assign the variable isActive on this which is now hopefully correctly assigned.
This has to do with how lambda function are implement in TS. this in arrow function is lexically inferred so it more in line with below code
function Person() {
var self = this; // Some choose that instead of self.
// Choose one and be consistent.
self.age = 0;
setInterval(function growUp() {
// The callback refers to the self variable of which
// the value is the expected object.
self.age++;
}, 1000);
}
So inside the lambda function it is not actually this but a context closer self. This may not be actual implementation but much closer to give you understanding of what is happening.
Now when you are outside the my impotent this refers to global var which would be window
The lambda function is similar to javascripts bind function.
Protip see your transpiled JS how your lambda function is transforming.

Calling this.function inside of jquery context [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
I am trying to call a function via this reference inside of jquery scope:
var Person = function(){
this.hello = function(){
console.log("hello!");
}
this.jump = function(){
$('.jump').on('click', function(){
this.hello();
});
}
}
Then I do:
var p = new Person();
When I click over the .jump element, the console prints an error describing that hello is not a function. I am not sure what is happening here, I am assumming that this is trying to call a function inside of jquery (not sure about it).
So, googling a little bit I found the Jquery.proxy() function that could be helpfull in my situation, but every time I try to understand it my head want to explote.
Use $.proxy() like so:
var Person = function(){
this.hello = function(){
console.log("hello!");
}
this.jump = function(){
$('.jump').on(
'click',
$.proxy(
function() {
this.hello();
},
this
)
);
}
}
Passing this as the 2nd argument to $.proxy() sends that context as the value of this inside the function defined in the first argument.
Try this,
var self = this;
this.jump = function(){
$('.jump').on('click', function(){
self.hello();
});
}
when you refer to "this" inside onclick, by default this refers to the DOM element found in the value of event.target
$('.jump').on('click', function(event) {
this.hello() /// <<-- this == event.target =~ $('.jump')
}
so, fortunately, you can use a closure
var self = this;
this.jump = function(){
$('.jump').on('click', function(){
self.hello();
});
}

Jquery each in method [duplicate]

This question already has answers here:
jquery using this to access object context when inside callback
(3 answers)
Closed 8 years ago.
I have a class Playlist :
function Playlist() {
this.episodes = [ /*episode list*/ ];
};
and I want to make a method displaying each episode :
Playlist.prototype.display = function() {
$('.episodeList').each(function(index) {
$(this).children('title').text(this.episodes[index].title);
});
}
The problem is that the 'this' at the end, before '.episodes[index]' represent the dom object selected and not my playlist.
How can I solve this problem ? Thanks.
Bind the function to your context:
$('.episodeList').each($.proxy(function(index, elem) {
$(elem).children('title').text(this.episodes[index].title);
}, this));
More on jQuery.proxy
If you use each on dom element, this inside each have reference to dom elements
For example:
Playlist.prototype.display = function(e)
{
$('.episodeList').each(function(index) {
console.log(this)
});
}
console.log prints dom element and it is correct.
Now put console log outside each like this:
Playlist.prototype.display = function(e)
{
console.log(this)
$('.episodeList').each(function(index) {
});
}
Now console.log should print PlayList function (your class). So "this" in each scope have reference to dom elements but this in Playlist.prototype.display scope have reference to Playlist function.
Solution is:
Playlist.prototype.display = function(e)
{
var self = this;
$('.episodeList').each(function(index) {
console.log(self)
console.log(this)
});
}
You need take "this" from Playlist scope and attribute to self var, so now self have refenrece to Playlist. Now you do each, so current this in each have reference to dom element but self variable still have reference to Playlist.
In your code $(this)=episodes[index] because it's in the each function. I think this is what you want,
Playlist.prototype.display = function() {
var element=$(this);
$('.episodeList').each(function(index,item) {
item.children('title').text(element.episodes[index].title);
});
}
A common practice in Javascript is to make a new variable for storing the current class, since the content of the this variable changes with context. Consider something like
function Playlist()
{
var self = this;
this.episodes = [/*episode list*/];
this.display = function()
{
$('.episodeList').each(function(index) {
$(this).children('title').text(self.episodes[index].title);
});
}
};
for your Playlist class definition, and call myPlaylist.display()
to display the content.

Getting an objects variable with events

function test() {
this.str = "hello";
this.sayHello = function() {
document.write(this.str);
}
this.init = function() {
document.onkeydown = this.sayHello;
}
}
var testing = new test();
testing.init();
The above code should output "hello" on an onkeydown event.
But I get "undefined". How can I get this to work ?
The problem is with this.sayHello. When you assign the reference to the sayHello function on keydown, the reference to the context (object) is lost. When a key is pressed, this refers to the Document object as the callback is invoked as:
document.onkeydown(); // or for simplicity imagine - document.sayHello();
If you assigned the str variable on the document object, you would see the value logged,
document.str = "hello";
However, that is not what you'd want. You need to wrap the keydown event handler inside another function to preserve the context to that object. Two ways to go about this. You could either wrap the event handler inside another function, and preserve the reference to this.
this.init = function() {
var me = this;
document.onkeydown = function() {
me.sayHello();
};
}
Or, if you're using modern browsers, this has already been incorporated into ECMAScript 5 using the bind function.
this.init = function() {
var me = this;
document.onkeydown = this.sayHello.bind(this);
}

Accessing this from within an object's inline function

I'm having difficulty referencing "this" from within a javascript inline function, within an object method.
var testObject = {
oThis : this,
testVariable : "somestring",
init : function(){
console.log(this.testVariable); // outputs testVariable as expected
this.testObject.submit(function(){
var anotherThis = this;
console.log(this.testVariable) // undefined
console.log(oThis.testVariable) // undefined
console.log(testObject.testVariable) // outputs testVariable
console.log(anotherThis.testVariable) // undefined
}
}
How do I access this.testVariable from within the submit function?
I'm also using jQuery as well, if that makes a difference.
I wonder if this is the best approach - and maybe I should have submit as a separate function, and then reference that inline, like:
init : function(){
this.testObject.submit = this.submitForm;
},
submitForm : function(){
// do validation here
console.log(this.testVariable) // outputs testvariable
.
.
.
return valid;
}
But this didn't seem to work either - and I think I'd just like to keep the submit function inline within my init method for now.
A common way is to assign the this you want to a local variable.
init: function() {
var _this = this;
this.testObject.submit(function() {
console.log(_this.testVariable); // outputs testVariable
});
}
You could also do this using ES6 arrow functions:
init: function(){
this.testObject.submit( () => {
console.log(this.testVariable);
}
}
Arrow functions capture the this value of the enclosing context, avoiding the need to assign this to a new variable, or to use bound functions.
The "this" variable is bound dynamically when a function — any function, regardless of where it was defined — is called.
Without seeing what that "submit" function is supposed to do, or where it's supposed to be used, it's hard to say how to change it. One thing you could do is to define "submit" in your "init" function:
init: function() {
// whatever
var instance = this;
instance.submitForm = function() {
console.log(instance.testVariable);
// ...
};
}
As long as "init" is called initially with "this" set to an instance of one of your objects, you should be good.
You can only access the oThis variable from the context of the object, which is lost because you are inside of another function. or through instantiating a new object. like this
var testInstance = new testObject();
Then you could access oThis by using:
testInstance.oThis;
but that would be redundant
I would try something like this Matt:
init: function(){
var self = this; // this allows you to access the parent object from different contexts
this.testObject.submit(function(){
console.log(self.testVariable);
}
A possible answer is to use arrow functions and pass in the object that "this" should refer to...
function create() {
var thing = { name: "thingy" };
thing.doStuff = function() {
alert(this.name);
}
thing.doStuff(thing);
}
The reason this works is arrow functions automatically have a final thisArg optional parameter which is bound to this.

Categories

Resources