Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scoping of 'this' in TypeScript

I have a very simple class, but already run into pain with the definition of ‘this’ in Typescript:

Typescript

/// <reference path='jquery.d.ts' />
/// <reference path='bootstrap.d.ts' />

module Problem {
    export class Index {
        detailsUrl: string;
        constructor() {
            $('.problem-detail-button').click((e) => {

                e.preventDefault();

                var $row = $(this).closest('tr'); //this must be that of the callback
                var problemId: number = $row.data('problem-id');

                $.ajax({
                    url: this.detailsUrl, //this must be the instance of the class
                    data: { id: problemId },
                    type: 'POST',
                    success: (result) => {
                        $('#details-modal-placeholder').html(result);
                        $('#details-modal-placeholder modal').modal('show');
                    },
                })
            });
        }
    }
}

Javascript

var Problem;
(function (Problem) {
    var Index = (function () {
        function Index() {
            var _this = this;
            $('.problem-detail-button').click(function (e) {
                e.preventDefault();
                var $row = $(_this).closest('tr');
                var problemId = $row.data('problem-id');
                $.ajax({
                    url: _this.detailsUrl,
                    data: {
                        id: problemId
                    },
                    type: 'POST',
                    success: function (result) {
                        $('#details-modal-placeholder').html(result);
                        $('#details-modal-placeholder modal').modal('show');
                    }
                });
            });
        }
        return Index;
    })();
    Problem.Index = Index;    
})(Problem || (Problem = {}));

Now the problem is that the line

var $row = $(this).closest('tr'); //this must be that of the callback

and this line

this.detailsUrl, //this must be the instance of the class

conflict in the meaning of 'this'

How do you handle the mixture of the 'this'?

like image 346
Oliver Avatar asked May 03 '13 14:05

Oliver


People also ask

What is scope in TypeScript?

Variable scopes in TypeScript:Here scope means the visibility of variable. The scope defines that we are able to access the variable or not. TypeScript variables can be of the following scopes: Local Scope:As the name specified, are declared within the block like methods, loops etc.

How do you use this in TypeScript?

The "this" keyword always points to the object that is calling a particular method. The type of "this" in an expression depends on the location in which the reference occurs: In a constructor, member function, or member accessor, this is of the class instance type of the containing class.

What variable scopes are in TypeScript?

The Typescript variables have three scopes. Global, Function and local. Using var you can create global & function variable.

What is ?: In TypeScript?

What does ?: mean in TypeScript? Using a question mark followed by a colon ( ?: ) means a property is optional. That said, a property can either have a value based on the type defined or its value can be undefined .


Video Answer


2 Answers

module Problem {
export class Index {
    detailsUrl: string;
    constructor() {
        var that = this;
        $('.problem-detail-button').click(function (e) {
            e.preventDefault();
            var $row = $(this).closest('tr'); //this must be that of the callback
            var problemId: number = $row.data('problem-id');

            $.ajax({
                url: that.detailsUrl, //this must be the instance of the class
                data: { id: problemId },
                type: 'POST',
                success: (result) => {
                    $('#details-modal-placeholder').html(result);
                    $('#details-modal-placeholder modal').modal('show');
                },
            })
        });
    }
}
}

Explicitly declare that = this so you have a reference for that.detailsUrl, then don't use a fat arrow for the click handler, so you get the correct this scope for the callback.

Playground.

like image 140
Jude Fisher Avatar answered Sep 22 '22 03:09

Jude Fisher


You need to fallback to the standard way of javascript. i.e store the variable as :

var self = this; 

Then you can use function instead of ()=> and use this to access variable in callback and self to access the instance of the class.

Here is the complete code sample:

module Problem {
    export class Index {
        detailsUrl: string;
        constructor() {
            var self = this; 
            $('.problem-detail-button').click(function(e){

                e.preventDefault();

                var $row = $(this).closest('tr'); //this must be that of the callback
                var problemId: number = $row.data('problem-id');

                $.ajax({
                    url: self.detailsUrl, //this must be the instance of the class
                    data: { id: problemId },
                    type: 'POST',
                    success: (result) => {
                        $('#details-modal-placeholder').html(result);
                        $('#details-modal-placeholder modal').modal('show');
                    },
                })
            });
        }
    }
}

// Creating 
var foo:any = {};
foo.x = 3;
foo.y='123';

var jsonString = JSON.stringify(foo);
alert(jsonString);


// Reading
interface Bar{
    x:number;
    y?:string; 
}

var baz:Bar = JSON.parse(jsonString);
alert(baz.y);

And your generated javascript:

var Problem;
(function (Problem) {
    var Index = (function () {
        function Index() {
            var self = this;
            $('.problem-detail-button').click(function (e) {
                e.preventDefault();
                var $row = $(this).closest('tr');
                var problemId = $row.data('problem-id');
                $.ajax({
                    url: self.detailsUrl,
                    data: {
                        id: problemId
                    },
                    type: 'POST',
                    success: function (result) {
                        $('#details-modal-placeholder').html(result);
                        $('#details-modal-placeholder modal').modal('show');
                    }
                });
            });
        }
        return Index;
    })();
    Problem.Index = Index;    
})(Problem || (Problem = {}));
var foo = {
};
foo.x = 3;
foo.y = '123';
var jsonString = JSON.stringify(foo);
alert(jsonString);
var baz = JSON.parse(jsonString);
alert(baz.y);
like image 35
basarat Avatar answered Sep 22 '22 03:09

basarat