Javascript - JQuery on () проблема с областью clearTimeout

Я искал и искал, и у меня ничего не получается, ребята. Помощь! Я наблюдаю за полем ввода (#filter_query) для событий keyup, используя JQuery on(). Когда пользователь вводит некоторый текст в это поле ввода, on() запускает setTimeout(), который, в свою очередь, запускает функцию поиска для сайта. Я пытаюсь избежать запуска поиска, если пользователь продолжает вводить в поле ввода, таким образом, clearTimeout(). По какой-то причине идентификатор тайм-аута не сохраняется для clearTimeout, и каждый раз создается новый идентификатор.

Вот мой код:

$(document).on('keyup', '#filter_query', function (event) {
    var iTimeoutID,
        iTypingDelay = 800,
        sFilterVal = $.trim($('#filter_query').val()),
        sFilterCat = $('#filter_catagory').val(),
        sFilterCol = $('#filter_col').val();

    clearTimeout(iTimeoutID);

    if (sFilterVal !== "") {
        iTimeoutID = setTimeout(
                    function () {
                        searchFunction();
                    },
                    iTypingDelay
                    );
    }
});

С приведенным выше кодом моя функция поиска срабатывает несколько раз независимо от clearTimeout(). Спасибо!


person Nykad    schedule 03.04.2012    source источник


Ответы (2)


Ваша iTimeoutID является локальной переменной для функции обработчика событий .on(), поэтому она уничтожается каждый раз, когда эта функция завершается, и воссоздается в следующий раз. Переместите его из этой области на более высокий уровень или на глобальный уровень, чтобы он мог пережить одно событие за другим.

Вы можете сделать это так;

var iTimeoutID = null;
$(document).on('keyup', '#filter_query', function (event) {
    var iTypingDelay = 800,
        sFilterVal = $.trim($('#filter_query').val()),
        sFilterCat = $('#filter_catagory').val(),
        sFilterCol = $('#filter_col').val();

    if (iTimeoutID) {
        clearTimeout(iTimeoutID);
        iTimeoutID = null;
    }

    if (sFilterVal !== "") {
        iTimeoutID = setTimeout(function() {
            iTimeoutID = null;
            searchFunction();
        }, iTypingDelay);
    }
});

Если вы хотите избежать глобальных переменных или у вас есть более одной из них, вы можете использовать jQuery .data() для хранения идентификатора таймера в объекте следующим образом:

$(document).on('keyup', '#filter_query', function (event) {
    var self = $(this);
    var iTimeoutID = self.data("timerID") || null;
    var iTypingDelay = 800,
        sFilterVal = $.trim($('#filter_query').val()),
        sFilterCat = $('#filter_catagory').val(),
        sFilterCol = $('#filter_col').val();

    if (iTimeoutID) {
        clearTimeout(iTimeoutID);
        iTimeoutID = null;
    }

    if (sFilterVal !== "") {
        iTimeoutID = setTimeout(function() {
            self.data("timerID", null);
            searchFunction();
        }, iTypingDelay);
    }
    self.data("timerID", iTimeoutID);
});

Вот еще одна версия, которая использует самовыполняющуюся функцию в качестве оболочки для некоторых переменных, которые могут сохраняться в обработчиках событий, не будучи глобальными:

(function() () {
    var iTimeoutID = null;
    $(document).on('keyup', '#filter_query', function (event) {
        var iTypingDelay = 800,
            sFilterVal = $.trim($('#filter_query').val()),
            sFilterCat = $('#filter_catagory').val(),
            sFilterCol = $('#filter_col').val();

        if (iTimeoutID) {
            clearTimeout(iTimeoutID);
            iTimeoutID = null;
        }

        if (sFilterVal !== "") {
            iTimeoutID = setTimeout(function() {
                iTimeoutID = null;
                searchFunction();
            }, iTypingDelay);
        }
    });
})();

Если это было что-то быстрое и вероятность конфликта с другим кодом была небольшой, а обработчик событий обслуживал только один объект, то первый вариант вполне подойдет.

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

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

person jfriend00    schedule 03.04.2012
comment
Добавлена ​​еще одна опция — самовыполняющаяся анонимная функция, которая действует как оболочка для неглобальных переменных, которые будут действовать через обработчик событий. - person jfriend00; 04.04.2012

Поскольку вы определяете переменную var iTimeoutID, это означает, что это не глобальная переменная и доступна только внутри этой функции. Поэтому, когда функция вызывается снова, она создает новую переменную.

Я считаю, что вы сможете исправить это, не объявляя переменную var iTimeoutID.

Я могу ошибаться, так что если это так, кто-нибудь, пожалуйста, поправьте меня.

person LeeR    schedule 03.04.2012
comment
Спасибо, но я всегда думал, что использование таких глобальных переменных не рекомендуется. Я не прав? Если да, то как лучше всего объявлять глобальные переменные? - person Nykad; 04.04.2012