0

Бьюсь уже пятый час и никак не могу понять в чем проблема. Есть класс в котором реализован методы загрузки и обновления данных и методы запуска и остановки таймера. По таймеру вызывается функция загрузки данных(loadData) в которой через ajax загружаются данные, в колбеке вызывается функция обновления данных(updateData) и вот здесь возникает проблема: браузер почему-то не может найти эту функцию ошибка "main.js:14 Uncaught TypeError: this.updateData is not a function"

function Runnable()
{
    this.timerID;
    this.loadData = function() {
        $.ajax({
            type: "POST",
            url: "ajax_handler.php",
            success: function(result) {
                try {
                    jsonObj = $.parseJSON(result);
                } catch (e) {
                    alert('Ошибка на сервере!');
                }
                //ВОТ ЗДЕСЬ ПРОБЛЕМА, ЭТА ФУНКЦИЯ НЕ НАЙДЕНА
                this.updateData(jsonObj);
            }
        });
    };

    this.updateData = function(events) {
        var countNewData = $(events).size();
        for (var i = 0; i < countNewData; i++) {
            $($('[id ^= "event_"]')[$('[id ^= "event_"]').size() - 1]).remove();
            $('#wrap').prepend('<div id="event_' + (countNewData - i) + '">' + events[i] + '</div>' );
        }
    };

    this.startTimer = function() {
        this.timerID = setInterval(this.loadData, 1000);
    };

    this.stopTimer = function() {
        clearInterval(this.timerID);
    };

}





$(document).ready( function() {
    var r = new Runnable();
    r.startTimer();
});
XYZ
  • 935
  • Вы уверены, что тут: "this.updateData(jsonObj);" у вас тот самый this, который вы ожидаете? – Alexander Karpov Jun 05 '16 at 07:16
  • Я не очень хорошо знаю js, но мне кажется что тут все правильно. Здесь должен вызываться метод updateData объекта r класса Runnable. – XYZ Jun 05 '16 at 07:22
  • я написал вам ответ, если мой вариант будет работать, то советую почитать вам про this в javascript. Он разный в разном контексте, нужно об этом помнить. – Alexander Karpov Jun 05 '16 at 07:24

2 Answers2

1

В яваскрипте значение this зависит от того как была объявлена функция, и от того как она вызывается. Подробнее можно узнать в справке

Конкретно в коде из вопроса this меняется дважды:

  1. this.timerID = setInterval(this.loadData, 1000); - таким образом this внутри функции loadData которая будет вызываться по таймеру - уже не будет объектом ожидаемого класса.

  2. $.ajax({ success: function(result) { - в данном случае this опять меняется на объект ajax.

Решений может быть несколько:

  1. сохранять значение this перед вызовом и использовать внутри не this, а сохраненную переменную
  2. использовать bind при передаче
  3. использовать стрелочные функции

    this.loadData = () => {
        $.ajax({
            success: (result) => {
                ...
                this.updateData(jsonObj);
            }
        });
    };
    
Grundy
  • 81,538
  • стрелочные же не все браузеры поддерживают) на бинд неправильная ссылка – Jean-Claude Jun 05 '16 at 11:52
  • @Jean-Claude, а я не сказал, что все поддерживают:) это всего лишь один из вариантов решения. На бинд поправил ссылку – Grundy Jun 05 '16 at 13:21
0

Вероятнее всего, что внутри $.ajax({... вы делаете обращение к вашей функции через this, но ваша функция объявлена в другом контексте, другими словами, внутри $.ajax({... другой this. Поправьте меня, если я не прав. Спасибо.
Попробуйте просто объявить

var updateData = function(events) {... 

а внутри $.ajax({...

вызвать вашу функцию так: updateData(jsonObj);

  • не, области видимости здесь ни при чем, здесь все в контекст вызова упирается – Grundy Jun 05 '16 at 08:57