2012-01-20 49 views
3

我有一個表中列出每行'筆記'字段。我希望能夠使用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循環,或其他東西的方式是什麼?任何建議將非常歡迎,謝謝!

回答

1

它不是直接回答你的問題,但我會親自做一個jQuery插件出你的代碼,你可以使用這樣的:

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

每個「提示欄上」將有它的實例插件封裝了專用於每個字段的計時器。無需擔心存儲在數組等。

有大量的插件模式和boilerplates有像this onethis 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

+0

這是一個很好的解決方案,謝謝 - 我從來沒有在jQuery中創建函數,所以它也非常有用。謝謝! –

+1

不客氣。我在jsfiddle上添加了一個工作[demo](http://jsfiddle.net/didierg/2sx8w/)。 –

4

這是我要做的事:

var t; 

$(document).ready(function() { 

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

     clearTimeout (t); 

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

    }); 

}); 

start_ajax() { 

    // Do AJAX. 

} 
+1

你是否忘記將超時設置爲t? 't = setTimeout('start_ajax()',3000);'??? – ppumkin

+0

謝謝。這是一個很好的解決方案,但不幸的是,我不認爲它可以像我一樣擁有多個定時器和註釋字段。 –

+0

@ppumkin:哎呦。我做了,修正了它。 – Jeffrey

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添加到數組中,只是在(可能?)不同的位置。另外,雖然我知道JavaScript允許它,我仍然認爲改變變量的類型是不好的做法。請保留timerVariable作爲陣列的索引,並在調用setTimeout時創建新變量,而不是重複使用timerVariable。它使您的代碼更容易遵循,並減少了引入錯誤的可能性。

最後,請致電setTimeout然後添加到您的陣列。你的代碼並沒有按照你的想法進行 - 你永遠不會將你調用setTimeout創建的引用添加到數組中。看看this jsFiddle看看實際發生了什麼。

+0

謝謝,這裏有一些很棒的建議和解釋,我將着眼於將它應用到我的代碼中。特別是我使用推送功能定義計時器的方式,哎呀! –

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>的當前狀態保存爲.data()緩存serverState
  • 每個可以改變輸入狀態(即鍵控,剪切,粘貼)的事件都會觸發一個延遲的函數調用(1000ms)。
  • 該功能檢查是否有一個正在進行的請求(serverState.busy),如果有(無需錘擊服務器請求)回退。
  • 當需要將更改發送到服務器(最後一個事件1000毫秒後)並且實際值已更改時,它會將新值發佈到服務器。
  • 在Ajax成功時,它將serverState設置爲新值,如果沒有,則爲錯誤。爲自己實現錯誤處理。

所以每按一次按鍵都會觸發該功能,但是最後一次按鍵後只有1000ms纔會將實際對值更改進行更改的按鍵推送到服務器。

+0

非常感謝,這是對我的代碼在許多方面的一個非常好的改進,我喜歡一些想法,但不幸的是,我有同樣的問題,它在每個按鍵上運行ajax,這意味着很多消息給用戶,很多電話到服務器 –

+0

@xndx:它當然不會。它在最後一次按鍵發生變化後1秒運行Ajax。 – Tomalak

+0

@xndx&Kyle感謝您的編輯! – Tomalak