Is there an alias for 'this' in TypeScript?

JqueryTypescript

Jquery Problem Overview


I've attempted to write a class in TypeScript that has a method defined which acts as an event handler callback to a jQuery event.

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin(onFocusIn);
    }

    onFocusIn(e: JQueryEventObject) {
        var height = this.textarea.css('height'); // <-- This is not good.
    }
}

Within the onFocusIn event handler, TypeScript sees 'this' as being the 'this' of the class. However, jQuery overrides the this reference and sets it to the DOM object associated with the event.

One alternative is to define a lambda within the constructor as the event handler, in which case TypeScript creates a sort of closure with a hidden _this alias.

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin((e) => {
            var height = this.textarea.css('height'); // <-- This is good.
        });
    }
}

My question is, is there another way to access the this reference within the method-based event handler using TypeScript, to overcome this jQuery behavior?

Jquery Solutions


Solution 1 - Jquery

The scope of this is preserved when using the arrow function syntax () => { ... } - here is an example taken from TypeScript For JavaScript Programmers.

var ScopeExample = { 
  text: "Text from outer function", 
  run: function() { 
    setTimeout( () => { 
      alert(this.text); 
    }, 1000); 
  } 
};

Note that this.text gives you Text from outer function because the arrow function syntax preserves the "lexical scope".

Solution 2 - Jquery

So as stated there is no TypeScript mechanism for ensuring a method is always bound to its this pointer (and this isn't just a jQuery issue.) That doesn't mean there isn't a reasonably straightforward way to address this issue. What you need is to generate a proxy for your method that restores the this pointer before calling your callback. You then need to wrap your callback with that proxy before passing it into the event. jQuery has a built in mechanism for this called jQuery.proxy(). Here's an example of your above code using that method (notice the added $.proxy() call.)

class Editor { 
    textarea: JQuery; 
 
    constructor(public id: string) { 
        this.textarea = $(id); 
        this.textarea.focusin($.proxy(onFocusIn, this)); 
    } 
 
    onFocusIn(e: JQueryEventObject) { 
        var height = this.textarea.css('height'); // <-- This is not good. 
    } 
} 

That's a reasonable solution but I've personally found that developers often forget to include the proxy call so I've come up with an alternate TypeScript based solution to this problem. Using, the HasCallbacks class below all you need do is derive your class from HasCallbacks and then any methods prefixed with 'cb_' will have their this pointer permanently bound. You simply can't call that method with a different this pointer which in most cases is preferable. Either mechanism works so its just whichever you find easier to use.

class HasCallbacks {
	constructor() {
		var _this = this, _constructor = (<any>this).constructor;
		if (!_constructor.__cb__) {
			_constructor.__cb__ = {};
			for (var m in this) {
				var fn = this[m];
				if (typeof fn === 'function' && m.indexOf('cb_') == 0) {
					_constructor.__cb__[m] = fn;					
				}
			}
		}
		for (var m in _constructor.__cb__) {
			(function (m, fn) {
				_this[m] = function () {
					return fn.apply(_this, Array.prototype.slice.call(arguments));						
				};
			})(m, _constructor.__cb__[m]);
		}
	}
}

class Foo extends HasCallbacks  {
	private label = 'test';
	
	constructor() {
		super();
		
	}
	
	public cb_Bar() {
		alert(this.label);
	}
}

var x = new Foo();
x.cb_Bar.call({});

Solution 3 - Jquery

As covered by some of the other answers, using the arrow syntax to define a function causes references to this to always refer to the enclosing class.

So to answer your question, here are two simple workarounds.

###Reference the method using the arrow syntax###

constructor(public id: string) {
	this.textarea = $(id);
	this.textarea.focusin(e => this.onFocusIn(e));
}

###Define the method using the arrow syntax###

onFocusIn = (e: JQueryEventObject) => {
	var height = this.textarea.css('height');
}

Solution 4 - Jquery

You can bind a member function to its instance in the constructor.

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin(onFocusIn);
        this.onFocusIn = this.onFocusIn.bind(this); // <-- Bind to 'this' forever
    }

    onFocusIn(e: JQueryEventObject) {
        var height = this.textarea.css('height');   // <-- This is now fine
    }
}

Alternatively, just bind it when you add the handler.

        this.textarea.focusin(onFocusIn.bind(this));

Solution 5 - Jquery

Try this

class Editor 
{

    textarea: JQuery;
    constructor(public id: string) {
        this.textarea = $(id);
        this.textarea.focusin((e)=> { this.onFocusIn(e); });
    }

    onFocusIn(e: JQueryEventObject) {
        var height = this.textarea.css('height'); // <-- This will work
    }

}

Solution 6 - Jquery

Steven Ickman's solution is handy, but incomplete. Danny Becket and Sam's answers are shorter and more manual, and fail in the same general case of having a callback that needs both dynamic and lexically scoped "this" at the same time. Skip to my code if my explanation below is TL;DR...

I need to preserve "this" for dynamic scoping for use with library callbacks, and I need to have a "this" with lexical scoping to the class instance. I argue that it is most elegant to pass the instance into a callback generator, effectively letting the parameter closure over the class instance. The compiler tells you if you missed doing so. I use a convention of calling the lexically scoped parameter "outerThis", but "self" or another name might be better.

The use of the "this" keyword is stolen from the OO world, and when TypeScript adopted it (from ECMAScript 6 specs I presume), they conflated a lexically scoped concept and a dynamically scoped concept, whenever a method is called by a different entity. I'm a little miffed at this; I would prefer a "self" keyword in TypeScript so that I can hand the lexically scoped object instance off of it. Alternately, JS could be redefined to require an explicit first-position "caller" parameter when it is needed (and thus break all web pages in one fell swoop).

Here's my solution (excised from a large class). Take a gander in particular at the way the methods are called, and the body of "dragmoveLambda" in particular:

export class OntologyMappingOverview {

initGraph(){
...
// Using D3, have to provide a container of mouse-drag behavior functions
// to a force layout graph
this.nodeDragBehavior = d3.behavior.drag()
        .on("dragstart", this.dragstartLambda(this))
        .on("drag", this.dragmoveLambda(this))
        .on("dragend", this.dragendLambda(this));

...
}

dragmoveLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void} {
    console.log("redefine this for dragmove");

    return function(d, i){
        console.log("dragmove");
        d.px += d3.event.dx;
        d.py += d3.event.dy;
        d.x += d3.event.dx;
        d.y += d3.event.dy; 
        
        // Referring to "this" in dynamic scoping context
        d3.select(this).attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
    
        outerThis.vis.selectAll("line")
            .filter(function(e, i){ return e.source == d || e.target == d; })
            .attr("x1", function(e) { return e.source.x; })
            .attr("y1", function(e) { return e.source.y; })
            .attr("x2", function(e) { return e.target.x; })
            .attr("y2", function(e) { return e.target.y; });
       
    }
}

dragging: boolean  =false;
// *Call* these callback Lambda methods rather than passing directly to the callback caller.
 dragstartLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void} {
        console.log("redefine this for dragstart");

        return function(d, i) {
            console.log("dragstart");
            outerThis.dragging = true;
          
            outerThis.forceLayout.stop();
        }
    }

dragendLambda(outerThis: OntologyMappingOverview): {(d: any, i: number): void}  {
        console.log("redefine this for dragend");

        return function(d, i) {
            console.log("dragend");
            outerThis.dragging = false;
            d.fixed = true;
        }
    }

}

Solution 7 - Jquery

TypeScript doesn't provide any extra way (beyond the regular JavaScript means) to get back to the 'real' this reference other than this remapping convenience provided in the fat arrow lambda syntax (which is allowable from a back-compat perspective since no existing JS code could be using a => expression).

You could post a suggestion to the CodePlex site, but from a language design perspective there's probably not much that can happen here, since any sane keyword the compiler could provide might already be in use by extant JavaScript code.

Solution 8 - Jquery

I have faced a similar problem. I think you can use .each() in many cases to keep this as a different value for later events.

The JavaScript way:

$(':input').on('focus', function() {
  $(this).css('background-color', 'green');
}).on('blur', function() {
  $(this).css('background-color', 'transparent');
});

The TypeScript way:

$(':input').each((i, input) => {
  var $input = $(input);
  $input.on('focus', () => {
    $input.css('background-color', 'green');
  }).on('blur', () => {
    $input.css('background-color', 'transparent');
  });
});

I hope this helps someone.

Solution 9 - Jquery

You can use js eval function: var realThis = eval('this');

Solution 10 - Jquery

You could store your reference to this in another variable.. self perhaps, and access the reference that way. I don't use typescript, but that's a method that's been successful for me with vanilla javascript in the past.

Solution 11 - Jquery

Check out this blog post http://lumpofcode.blogspot.com/2012/10/typescript-dart-google-web-toolkit-and.html, it has a detailed discussion of techniques for organizing calls within and across TypeScript classes.

Solution 12 - Jquery

There is much simpler solution than all the above answers. Basically we fall back to JavaScript by using key word function instead of using '=>' construct which will translate the 'this' into class 'this'

class Editor {
    textarea: JQuery;

    constructor(public id: string) {
        var self = this;                      // <-- This is save the reference
        this.textarea = $(id);
        this.textarea.focusin(function() {   // <-- using  javascript function semantics here
             self.onFocusIn(this);          //  <-- 'this' is as same as in javascript
        });
    }

    onFocusIn(jqueryObject : JQuery) {
        var height = jqueryObject.css('height'); 
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionToddView Question on Stackoverflow
Solution 1 - JqueryFentonView Answer on Stackoverflow
Solution 2 - JquerySteven IckmanView Answer on Stackoverflow
Solution 3 - JquerySamView Answer on Stackoverflow
Solution 4 - JqueryDrew NoakesView Answer on Stackoverflow
Solution 5 - JqueryGabriel C.View Answer on Stackoverflow
Solution 6 - JqueryEricView Answer on Stackoverflow
Solution 7 - JqueryRyan CavanaughView Answer on Stackoverflow
Solution 8 - JqueryobrysView Answer on Stackoverflow
Solution 9 - JqueryreptileView Answer on Stackoverflow
Solution 10 - JquerySheridan BulgerView Answer on Stackoverflow
Solution 11 - JqueryEzwardView Answer on Stackoverflow
Solution 12 - JqueryDerek LiangView Answer on Stackoverflow