Определение области 'this' в TypeScript

У меня очень простой класс, но я уже столкнулся с болью с определением 'this в 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 = {}));

Теперь проблема в том, что строка

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

и эта строка

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

конфликт в значении 'this'

Как вы обрабатываете смесь 'this'?

Ответ 1

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');
                },
            })
        });
    }
}
}

Явно объявляю that = this, поэтому у вас есть ссылка для that.detailsUrl, затем не используйте жирную стрелку для обработчика кликов, поэтому вы получите правильную область this для обратного вызова.

Игровая площадка.

Ответ 2

Вам нужно вернуться к стандартному способу javascript. сохраните переменную как:

var self = this; 

Затем вы можете использовать function вместо ()=> и использовать this для доступа к переменной в обратном вызове и self для доступа к экземпляру класса.

Вот полный пример кода:

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);

И ваш сгенерированный 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);

Ответ 3

Если вы поддерживаете только браузеры с .addEventListener, я бы предложил использовать это, чтобы связать ваши данные с вашими элементами.

Вместо того, чтобы внедрять ваш код, я просто приведу простой пример.

function MyClass(el) {
    this.el = el;
    this.foo = "bar";
    el.addEventListener("click", this, false);
}

MyClass.prototype.handleEvent = function(event) {
    this[event.type] && this[event.type](event);
};

MyClass.prototype.click = function(event) {
    // Here you have access to the data object
    console.log(this.foo); // "bar"

    // ...and therefore the element that you stored
    console.log(this.el.nodeName); // "DIV"

    // ...or you could use `event.currentElement` to get the bound element
};

Таким образом, этот метод дает вам организованную связь между элементами и данными.

Даже если вам нужно поддерживать старый IE, вы можете закрепить его с помощью .attachEvent().

Итак, чтобы использовать его, вы просто передаете элемент конструктору при настройке данных.

new MyClass(document.body);

Если вся логика находится в вашем обработчике (-ах), вам даже не нужно указывать ссылку на созданный объект, поскольку обработчики автоматически получают ее через this.

Ответ 4

Я обычно привязываю this к переменной, как только у меня есть ее в области, которую я хочу.

Однако this вы можете найти следующее:

constructor() {
    var class_this=this;
    $('.problem-detail-button').click(function (e) {
        e.preventDefault();
        var callback_this=e.target;

Ответ 5

Поздно к потоку, но у меня есть что-то другое, чем предложение.

Вместо:

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

Рассмотрим использование:

var $row = $(e.currentTarget).closest('tr');

Как и в этом примере, где угодно, вы можете использовать this в обратном вызове jQuery, у вас есть доступ к параметру функции, который вы можете использовать вместо этого. Я бы предположил, что использование этих параметров вместо this является более чистым (где "чище" определяется как более выразительное и менее вероятно, что оно будет превращено в ошибку во время будущего обслуживания).

Ответ 6

module Problem {
export class Index {
    constructor() {
        $('.classname').on('click',$.proxy(this.yourfunction,this));
    }
    private yourfunction(event){
        console.log(this);//now this is not dom element but Index
    }
}
}

проверьте jquery.proxy(). просто напомните, что есть другой способ.