Ajax - 但仅限于用户停止输入时

时间:2012-01-20 09:26:16

标签: javascript jquery arrays timer

我有一个表格列表,每行都有一个'notes'字段。我希望能够使用ajax更新它们并在更新后显示一条消息,但我很难找出正确的代码。

我的计划是捕获按键,然后将音符ID传递给计时器,每次用户按下按键时都会重置该计时器,这样只有在他们停止输入1秒后才会运行。问题是,如果页面上有多个注释,我需要将它传递给一个数组并在每个数组上重置计时器,如果可能的话?

这是我的代码:

    var waitTime = 1000;
    var click = false;
    var timers = new Array();

    $('.notes').keyup(function(){

        var timerVariable = $(this).attr('id').split("-");
        timerVariable = timerVariable[0];
        timerVariable = timerVariable.replace('note', '');

        timers.push(timerVariable);
        timers[timerVariable] = timerVariable;

        if(click==false){
            var id = $(this).attr('id');
            if(click==false){
                click= true;
                timerVariable = setTimeout(function(){doneTyping(id)}, waitTime);
            }
        }
    });

    $('.notes').keydown(function(){
        for (var timer in timers) {
            clearTimeout(timer);
        }
        click = false;
    });

    function doneTyping (id) {
        var staffNo = id.split("-");
        staffNo = staffNo[0];
        staffNo = staffNo.replace('note', '');

        var data = 'data='+id+'&note='+$('#'+id).val();
        $.ajax({
            url: "update-notes.php", 
            type: "GET",       
            data: data,    
            cache: false,
            success: function (html) {
                jGrowlTheme('mono', 'Updated ' + staffNo, 'Thank you, the note has been updated.', 'tick.png');
            }
        });
    }

我想知道问题是否可能与我调用for循环或其他方式有关?非常欢迎任何建议,谢谢!

4 个答案:

答案 0 :(得分:4)

我就是这样做的:

var t;

$(document).ready(function() {

    $('#search_string').keyup(function() {

        clearTimeout (t);

        t = setTimeout('start_ajax()', 3000);

    });

});

start_ajax() {

    // Do AJAX.

}

答案 1 :(得分:1)

这不是你问题的直接答案,但我会亲自从你的代码中创建一个jquery插件,你可以这样使用:

$('.note-fields').myNoteAjaxPlugin({ waitFor: '1000'  });

每个“注释字段”都有它的插件实例,封装了专用于每个字段的计时器。无需担心存储在数组等中。

有很多插件模式和样板,例如 this one this other one

以下是一个示例实现。我使用了一个样板并将其与jquery ui桥代码(它检查私有方法,重新使用以前的插件实例或正确实例化)合并:

;(function ( $, window, document, undefined ) {

    // Create the defaults once
    var pluginName = 'myNoteAjaxPlugin',
        defaults = {
            waitFor: "1000",
        };

    // The actual plugin constructor
    function Plugin( element, options ) {

        this.element = element;
        this.$element = $(element);

        this.options = $.extend( {}, defaults, options) ;

        this._defaults = defaults;
        this._name = pluginName;

        this._timer = null;
        this._click = false;

        this._init();
    }

    Plugin.prototype._init = function () {

        var self = this;

        this.$element.keyup(function(e){

            if( self._click === false ){
                var id = self.element.id;
                if( self._click === false ){
                    self._click = true;
                    self._timer = setTimeout(function(){self._doneTyping(id)}, self.options.waitFor);
                }
            }
        });

        this.$element.keydown(function(e) {

            if (self._timer) {
                clearTimeout(self._timer);
            }
            self._click = false;

        });

    };

    Plugin.prototype._doneTyping = function(id) {

        alert('done typing');

    };

    $.fn[pluginName] = function( options ) {

        var isMethodCall = typeof options === "string",
            args = Array.prototype.slice.call( arguments, 1 ),
            returnValue = this;

        // allow multiple hashes to be passed on init
        options = !isMethodCall && args.length ?
            $.extend.apply( null, [ true, options ].concat(args) ) :
            options;

        // prevent calls to internal methods
        if ( isMethodCall && options.charAt( 0 ) === "_" ) {
            return returnValue;
        }

        if ( isMethodCall ) {
            this.each(function() {
                var instance = $.data( this, pluginName ),
                    methodValue = instance && $.isFunction( instance[options] ) ?
                        instance[ options ].apply( instance, args ) :
                        instance;

                if ( methodValue !== instance && methodValue !== undefined ) {
                    returnValue = methodValue;
                    return false;
                }
            });

        } else {
            this.each(function() {
                var instance = $.data( this, pluginName );
                if ( instance ) {
                    instance.option( options || {} )._init();
                } else {
                    $.data( this, pluginName , new Plugin( this , options) );
                }
            });
        }

        return returnValue;
    };

})( jQuery, window, document );


$('#myinput').myNoteAjaxPlugin({waitFor: '1500'});

工作DEMO

答案 2 :(得分:1)

问题可能出在这部分代码中:

$('.notes').keyup(function(){
    var timerVariable = $(this).attr('id').split("-");
    timerVariable = timerVariable[0];
    timerVariable = timerVariable.replace('note', '');

    timers.push(timerVariable);
    timers[timerVariable] = timerVariable;

    if(click==false){
        var id = $(this).attr('id');
        if(click==false){
            click= true;
            timerVariable = setTimeout(function(){doneTyping(id)}, waitTime);
        }
    }
});

我不确定你为什么timers.push(timerVariable);紧随其后timers[timerVariable] = timerVariable; - 他们都将timerVariable添加到数组中,只是在(可能?)不同的位置。< / p>

此外,虽然我知道Javascript允许它,但我仍然认为改变变量的类型是不好的做法。保留timerVariable作为数组的索引,并在调用setTimeout时创建一个新变量,而不是重用timerVariable。它使您的代码更容易理解,并减少引入错误的可能性。

最后,请致电setTimeout 然后添加到您的阵列。您的代码没有按照您的想法执行 - 您实际上从未将setTimeout调用创建的引用添加到数组中。看看this jsFiddle,看看实际发生了什么。

答案 3 :(得分:1)

考虑更精简的代码版本:

$('.notes')
.each(function () {
    $(this).data("serverState", {busy: false, date: new Date(), val: $(this).val() });
})
.bind("keyup cut paste", function() {
    var note = this, $note = $(this), serverState = $note.data("serverState");

    setTimeout(function () {
        var val = $note.val();

        if ( 
            !serverState.busy
            && new Date() - serverState.date > 1000 && val != serverState.val 
        ) {
            $.ajax({
                url: "update-notes.php", 
                type: "POST",       
                data: { data: note.id, note: val },
                cache: false,
                success: function (html) {
                    var staffNo = note.id.split("-")[0].replace('note', '');

                    serverState.date = new Date();
                    serverState.val  = val;
                    jGrowlTheme('mono', 'Updated ' + staffNo, 'Thank you, the note has been updated.', 'tick.png');
                },
                error: function () {
                    // handle update errors
                }, 
                complete: function () { 
                    serverState.busy = false;
                }
            });
        }
    }, 1000);
});
  • 最初,每个<input>的当前状态将保存为serverState缓存中的.data()
  • 每个可以改变输入状态的事件(即keyup,cut,paste)都会触发延迟函数调用(1000ms)。
  • 该函数检查是否已有正在进行的请求(serverState.busy),如果有请求则退出(不需要通过请求锤击服务器)。
  • 当需要将更改发送到服务器(最后一个事件后1000毫秒)并且值实际已更改时,它会将新值发布到服务器。
  • 在Ajax成功时,它将serverState设置为新值,而不是错误。为自己实现错误处理。

因此,每次按键都会触发该功能,但在最后一次按键后实际更改值更改的1000ms被推送到服务器。