Ambiguous 'this' inside jquery callback [duplicate] - javascript

This question already has answers here:
"this" keyword in event methods when using JavaScript prototype object
(4 answers)
Closed 8 years ago.
My problem is the context of 'this' inside jquery callback.
$('input').on('change', function(){
this.number = $(this).val();
});
Above, this is the input element, which is normally what we want 'this' to be. The problem is that when it becomes a method of an object as below.
// constructor pattern
var View = function(){
this.number = 0;
};
// method definition
View.prototype.foo = function(){
$('input').on('change', function(){
// former this should be the object instance and
// the latter should be the html element.
this.number = $(this).val();
});
};
To change the context of this of the function, Function.bind() can be used as below.
View.prototype.foo = function(){
$('input').on('change', function(){
this.number = $(this).val();
}.bind(this)); // bind the callback to the instance of View object
};
Above works until $(this).val() since then $(this) wants the input element back not the View object.
In order to solve this in ad-hoc manner, I can explicitly set this to be the name of an instance as below.
View.prototype.foo = function(){
$('input').on('change', function(){
// explicitly set this to be the instance
// while sacrificing generality since code breaks when the object name is not 'view'
view.number = $(this).val();
});
};
var view = new View();
As you can see, this can resolve ambiguity of this but also compromises generality since code breaks when the object name is not 'view'.
Given above, how can I make the code resolve ambiguity while not compromising generality?
Please suggest a way. Thank you.

A common approach used in many lib/frameworks is as following:
View.prototype.foo = function(){
var self = this; // store this as a local variable
$('input').on('change', function(){
self.number = $(this).val();
});
};

Related

"This" within es6 class method [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
For some reason I'm getting weird values for "this" in my es6 class...
'use strict';
class Clicker {
constructor(element) {
this.count = 0;
this.elem = element;
this.elem.addEventListener('click', this.click);
// logs Clicker { count:0, elem: button#thing} as expected
console.log(this);
}
click() {
// logs <button id="thing">...</button> as unexpected...
console.log(this);
this.count++;
}
}
var thing = document.getElementById('thing');
var instance = new Clicker(thing);
<button id="thing">Click me</button>
Question:
Why is the "this" inside of of the Clickers' click method referring to the dom node rather than ... itself?
More importantly, how do I refer to Clickers' count property from within its' click method if I can't use "this" to do it?
Why is the "this" inside of of the Clickers' click method referring to
the dom node rather than ... itself?
Because the specification for .addEventListener() is to set the this pointer to the DOM element that caught the event. That's how it is designed to work.
When passing a method as a callback where you want to override the value of this, you can use .bind() to force the desired value of this with it:
this.elem.addEventListener('click', this.click.bind(this));
Explanation:
All function calls in Javascript set a new value of this according to how the function is called. See this explanation for further info on that basic set of rules.
On top of that, when you do this:
this.elem.addEventListener('click', this.click);
You are just getting the this.click method and passing that method alone to addEventListener(). The value of this will be completely lost. It's as if you are doing this:
var m = this.click; // m here is just a reference to Clicker.prototype.click
this.elem.addEventListener('click', m);
On top of this, .addEventListener() is specifically built to set it's own value of this when it calls the callback (to point this at the element creating the event).
So, you can use .bind() as shown above to force the proper value of this to be in place when your method is called.
For reference, you may find this description of the six ways that this is set for a function call in Javascript to be useful.
Other Options
I find .bind() to be the clearest way of defining this, but you could also use either a local anonymous function:
var self = this;
this.elem.addEventListener('click', function() {
self.click();
});
or in ES6, an arrow function:
this.elem.addEventListener('click', () => this.click());
The arrow function will preserve the value of this for you automatically to avoid needing the self reference used in the prior example.

What is use of self in jquery/ javascript?

In javascript they are using like:
var self=this;
var jquery_element= $(html_element);
self.jquery_element=jquery_elemnet
Why do we use these in javascript. I got this code from OpenStack horizon
var self=this; is useful for when you have nested functions and this can become ambiguous (in case you dont know this is a javascript keyword). self can be used to still change the this that now reffers to the this from the inner function.
var jquery_element= $(html_element); just provides a easy way to reference the jQuery element without having to constantly recreate it (also provides performance benefit for instance explained here).
self.jquery_element = jquery_element appears to be specific to that code and I'm not quite sure what it does.
It is for visibility in other scope, for using this from one scope, within other scope. Edit.
var parentFunction = function(){
this.msg = "hello world";
var parentScopeSelf = this;
var innerFunction = function(){
var innerFunctionScopeSelf = this;
console.log(this.msg);// undefined (because this now is innerFunction scope, and does not have property msg)
console.log(innerFunctionScopeSelf.msg);// undefined (because innerFunctionScopeSelf is "this" from innerFunction scope, and does not have property msg)
console.log(parentScopeSelf.msg);// hello world (because parentScopeSelf is "this" from parentFunction scope)
}
}
To answer your direct question, this is a javascript keyword, and its value will change depending on its location. By writing its value to a regular variable like self, you are preserving the value wherever self is in scope, even if this itself has changed.
Assigning this to another variable is useful when you have nested functions. For instance:
jQuery(function($) {
$('#myInput').on('keyup', function() {
var $this = $(this); // assign the jQuery's element to $this
$('div.errors').each(function() {
console.log($(this)); // outputs jQuery's object div.errors
console.log($this); // the input is still available in the nested function
});
});
});
As a recommendation, if a variable stores a jQuery element, please prepend it with $. Therefore, it should be
var $jquery_element = $(html_element);
var jquery_element= $(html_element);
is to make the html element be a jquery object that can be use with all the method of jquery.
html_element.fadeOut(); <-- will not work
$(html_element).fadeOut(); <-- will work

javascript Object - unreachable method [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
I have a javascript object with a handful of methods, and some of the methods reference each other. The methods become undefined in some situations, regardless of using the key word "this" with them. I'm not sure how to go about it. Here is a snippet of my object below. Method getContent() when accessed in onClickMngLinksBtn method becomes undefined when a button with onClickMngLinksBtn event binding is clicked. This same method works fine when accessed with:
InLineLinksObj.getContent()
I'm hoping the solution is something very basic to Objects in javascript. Any help is much appreciated.
function InLineLinks(formController, fieldController)
{
....
this.getContent = function(){
var field = this.getFieldController().getCustomFieldByName(this.content_field);
if(field){
return field.getValue();
}
return null;
};
this.onClickMngLinksBtn = function(){
var links = [];
var txt = this.getContent();
}
....
}
See here, here or here, or many other places for an explanation of scope and the this keyword in javascript. Essentially,
this always refers to the “owner” of the function we're executing
and when your method is triggered by a DOM event, then the owner is either the window or the HTML element that was clicked (or moused over, etc.), instead of the containing object.
A simple way around it in your case is to define a second variable self which will retain a reference to the containing object.
function InLineLinks(formController, fieldController) {
var self = this;
....
self.getContent = function(){
var field = self.getFieldController().getCustomFieldByName(self.content_field);
if(field){
return field.getValue();
}
return null;
};
self.onClickMngLinksBtn = function(){
var links = [];
var txt = self.getContent();
}
....
}
The way you have it, InLineLinks is a constructor and getContent is a method of it's instances.
Then, you must instantiate InLineLinks to reach getContent:
new InLineLinks().getContent()

Best way to send "this" object to callback function [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 8 years ago.
Lately a lot of my code has been looking like this...
function MyObjectClass (selector) {
this.color = "red";
this.$elt = $(selector);
// ... any other object vars here ...
// Example method for the object
this.showThenUpdateColor = function () {
// Keep a copy of "this" to use for callbacks
var o = this;
// Example of jQuery function that accepts a callback
o.$elt.fadeIn(function(){
// Inside of this callback function we need to access the main object
o.$elt.css({
"background-color" : o.color // This is where we need the "o"
});
});
}
}
var myObject = new MyObjectClass('#myObject');
myObject.showThenUpdateColor();
...where I have a callback inside of an object method. Typically I assign the object itself ("this") to a local variable (usually "o" because it's short and easy) which can be used in the callback.
Is this an optimal use of memory? Is there any danger of memory leaks? Is there a better way?
I would recommend having a look at jQuery.proxy(). It lets you create a function that, when executed, executes another function in the scope you specify. You could then write:
this.showThenUpdateColor = function () {
// Example of jQuery function that accepts a callback
this.$elt.fadeIn($.proxy(this._onFadeInComplete, this));
}
function _onFadeInComplete() {
this.$elt.css({
"background-color" : this.color
});
}

Javascript: Object context lost when calling private function [duplicate]

This question already has answers here:
Javascript: Do I need to put this.var for every variable in an object?
(6 answers)
Closed 8 years ago.
i have a simple Javascript "class" im testing right now. I noticed that "this" in my private functions do not point to the object itself, instead, its pointing to the global scope (window).
Why?
Info: i want to keep mode private, so i used var mode instead of this.mode.
I also want to keep both internal functions private, so user has no access to it.
I basically use .prototype to add public functions to myStorage accessing private members with this.
My code:
var myStorage = function(mymode) {
var mode = mymode;
function privateFunctionA() {
// access this.mode to read mymode from constructor but
// this is pointing to window
};
function privateFunctionB() {
// access this.mode to read mymode from constructor but
// this is pointing to window
};
// check for indexeddb, websql and localstorage
if(mymode == 'A') {
privateFunctionA();
} else {
privateFunctionB();
}
};
myStorage.prototype.publicFunc = function() {
console.log(this.mode); // does this work?
}
var data = new myStorage();
this is always function scoped in JavaScript (unless you pass in a context explicitly using call() or apply(). Therefore, in your private functions, this no longer refers to the same this as in the parent scope. An idiomatic way of handling this in JavaScript is to assign this to a self var in the parent scope. E.g.,
var myStorage = function(mymode) {
var self = this;
var mode = mymode;
function privateFunctionA() {
console.log(self);
};
...
};
Regarding this snippet:
myStorage.prototype.publicFunc = function() {
console.log(this.mode); // does this work?
}
You will need to assign mode to this back in your constructor (instead of as a var). So, the constructor would now become:
var myStorage = function(mymode) {
var self = this;
this.mode = mymode;
function privateFunctionA() {
// works
console.log(self.mode);
};
...
};
And this.mode will also work in your .publicFunc() in this case.
As one more stylistic note, constructor functions in JavaScript usually use proper camel case (i.e., MyStorage).
I dont think you can access the object itself with this when using prototype, because the scope changes and you loose the reference to the primary object itself, so this becomes the window instead.
Check this other question in order to get some more info:
Use of 'prototype' vs. 'this' in JavaScript?
Hope this helps.

Categories

Resources