入力/書き込みを停止した後、入力テキストでイベントをトリガーするにはどうすればよいですか?


84

入力テキストボックスへの文字の入力を(入力中ではなく)停止した直後にイベントをトリガーしたい。

私は試しました:

$('input#username').keypress(function() {
    var _this = $(this); // copy of this object for further usage

    setTimeout(function() {
        $.post('/ajax/fetch', {
            type: 'username',
            value: _this.val()
        }, function(data) {
            if(!data.success) {
                // continue working
            } else {
                // throw an error
            }
        }, 'json');
    }, 3000);
});

しかし、この例では、入力されたすべての文字に対してタイムアウトが発生し、20文字を入力すると約20のAJAXリクエストが発生します。

このフィドルでは、AJAXの代わりに単純なアラートを使用して同じ問題を示します。

これに対する解決策はありますか、それとも私はこれに悪いアプローチを使用していますか?


1
javascriptは、ユーザーが入力フィールドへの入力を停止したときに通知を受け取ることができるイベントを提供していないのではないかと思います。なぜそれが必要なのですか?
ダリンディミトロフ2012

3
例から明らかではありませんか?20個のリクエストを送信する代わりに、「エンドユーザーが入力を停止したとき」にイベントをトリガーしたい

1
ユーザーが手動でフィールドを送信または変更しない限り、ユーザーが実際に入力を完了したことを知る方法はありません。ユーザーが文の途中で一時停止し、さらに入力する前に5分間待機するかどうかをどのように知ることができますか?考えられる解決策は、.blur()を使用して、ユーザーのフォーカスがフィールドを離れたときに送信することです。
ケビンM

14
上記のコメントはばかげています。これは一般的な使用例です。ユーザーがウィンドウのサイズ変更、マップのズーム、ドラッグ、入力を完了したときに1つのイベントが必要です。基本的に、ユーザー側の継続的なアクションはすべて、デジタルユニバースに変換する必要があります。1回のキーストロークでもこの問題が発生します。キーを押すと、実際には「バウンス」して、1つのキーストロークイベントだけでなく、多くのイベントが作成されます。コンピューターのハードウェアまたはOSはこれらの余分なイベントを削除します。そのため、個別のキーストロークイベントのように見えます。これは「デバウンス」と呼ばれ、OPが必要とするものです。
ジギー2013年

反応ユーザーへの警告:stackoverflow.com/a/28046731/57883
Maslow

回答:


172

(あなたがそうであるように)を使用するsetTimeout必要がありますが、制限をリセットし続けることができるように参照も保存する必要があります。何かのようなもの:

//
// $('#element').donetyping(callback[, timeout=1000])
// Fires callback when a user has finished typing. This is determined by the time elapsed
// since the last keystroke and timeout parameter or the blur event--whichever comes first.
//   @callback: function to be called when even triggers
//   @timeout:  (default=1000) timeout, in ms, to to wait before triggering event if not
//              caused by blur.
// Requires jQuery 1.7+
//
;(function($){
    $.fn.extend({
        donetyping: function(callback,timeout){
            timeout = timeout || 1e3; // 1 second default timeout
            var timeoutReference,
                doneTyping = function(el){
                    if (!timeoutReference) return;
                    timeoutReference = null;
                    callback.call(el);
                };
            return this.each(function(i,el){
                var $el = $(el);
                // Chrome Fix (Use keyup over keypress to detect backspace)
                // thank you @palerdot
                $el.is(':input') && $el.on('keyup keypress paste',function(e){
                    // This catches the backspace button in chrome, but also prevents
                    // the event from triggering too preemptively. Without this line,
                    // using tab/shift+tab will make the focused element fire the callback.
                    if (e.type=='keyup' && e.keyCode!=8) return;
                    
                    // Check if timeout has been set. If it has, "reset" the clock and
                    // start over again.
                    if (timeoutReference) clearTimeout(timeoutReference);
                    timeoutReference = setTimeout(function(){
                        // if we made it here, our timeout has elapsed. Fire the
                        // callback
                        doneTyping(el);
                    }, timeout);
                }).on('blur',function(){
                    // If we can, fire the event since we're leaving the field
                    doneTyping(el);
                });
            });
        }
    });
})(jQuery);

$('#example').donetyping(function(){
  $('#example-output').text('Event last fired @ ' + (new Date().toUTCString()));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<input type="text" id="example" />
<p id="example-output">Nothing yet</p>

次の場合に実行されます。

  1. タイムアウトが経過した、または
  2. ユーザーがフィールドを切り替えた(blurイベント)

(いずれか早い方)


1
ええ、これは私の夜を救います。ありがとう
初心者2013年

2
@Brad:このjqueryソリューションは、入力ボックスに入力されたバックスペースキーが最新のchrome(38.0.2125.111)で検出されないことを除いて、正常に機能します。keyup動作するように変更するだけです。これを調べて、コードを適切に変更することをお勧めします。
palerdot 2014年

1
@palerdot:知ってよかった、ありがとう。私はそれを調べて、変更があれば投稿します。
Brad Christie

3
このプラグインをありがとう-うまくいきます。誰かが入力フィールドに何かを貼り付けたときに機能しないため、1つの調整を行う必要がありました。私は、次の行を編集しましたpaste -$el.is(':input') && $el.on('keyup keypress paste',function(e){
マット・

1
@ Sangar82:今すべきです(少し混乱していますが、右クリック
Brad Christie

71

解決:

これが解決策です。ユーザーが指定された時間入力を停止した後に関数を実行する:

var delay = (function(){
  var timer = 0;
  return function(callback, ms){
  clearTimeout (timer);
  timer = setTimeout(callback, ms);
 };
})();

使用法

$('input').keyup(function() {
  delay(function(){
    alert('Hi, func called');
  }, 1000 );
});

1
user1386320-この解決策を確認してください。同様の問題があり、機能しました。alert()の代わりにコードを追加します。
ata ul Mustafa

ありがとう。うまく機能します。
user1919 2015年

2
N +アップ投票を追加できますか?このソリューションは、JavaScriptクロージャを使用して、見事で、短く、エレガントです。
Matteo Conta 2016年

1
@ MatteoConta、ありがとうございます:)
Ata ul Mustafa

1
このためだけにunderscore.jsをページに含めたくありませんでした。あなたのソリューションは完璧に機能します!ありがとう
Skoempie 2018

17

underscore.jsの「デバウンス」を使用できます

$('input#username').keypress( _.debounce( function(){<your ajax call here>}, 500 ) );

これは、500msのキーを押した後に関数呼び出しが実行されることを意味します。ただし、500ミリ秒前に別のキーを押すと(別のキー押下イベントが発生します)、前の関数の実行は無視(デバウンス)され、新しい500ミリ秒のタイマーの後に新しい関数が実行されます。

追加情報については、_。debounce(func、timer、true)を使用すると、最初の関数が実行され、後続の500msタイマーを伴う他のすべてのキー押下イベントが無視されます。


すでにlibとしてアンダースコアを付けている場合は、非常に便利で短いです。
Francesco Pasa 2017年


6

洗浄液:

$.fn.donetyping = function(callback, delay){
  delay || (delay = 1000);
  var timeoutReference;
  var doneTyping = function(elt){
    if (!timeoutReference) return;
    timeoutReference = null;
    callback(elt);
  };

  this.each(function(){
    var self = $(this);
    self.on('keyup',function(){
      if(timeoutReference) clearTimeout(timeoutReference);
      timeoutReference = setTimeout(function(){
        doneTyping(self);
      }, delay);
    }).on('blur',function(){
      doneTyping(self);
    });
  });

  return this;
};

5

setTimeout変数に割り当てclearTimeout、キーを押すとそれをクリアするために使用する必要があります。

var timer = '';

$('input#username').keypress(function() {
  clearTimeout(timer);
  timer = setTimeout(function() {
    //Your code here
  }, 3000); //Waits for 3 seconds after last keypress to execute the above lines of code
});

フィドル

お役に立てれば。


3

私が作ったいくつかの簡単なプラグインがあります。提案されたソリューションよりもはるかに少ないコードで済み、非常に軽量です(〜0,6kb)

まずBidbumpedいつでもできるよりもオブジェクトを作成します。すべてのバンプは、次に指定された時間の間、入札コールバックの起動を遅らせます。

var searchBid = new Bid(function(inputValue){
    //your action when user will stop writing for 200ms. 
    yourSpecialAction(inputValue);
}, 200); //we set delay time of every bump to 200ms

ときにBidオブジェクトが準備ができて、我々はする必要がありbump何とか。にバンピングを付けましょうkeyup event

$("input").keyup(function(){
    searchBid.bump( $(this).val() ); //parameters passed to bump will be accessable in Bid callback
});

ここで何が起こるかです:

ユーザーがキーを押すたびに、入札は次の200ミリ秒間「遅延」(バンプ)されます。再び「ぶつかる」ことなく200msが経過すると、コールバックが発生します。

また、入札を停止するための2つの追加機能(ユーザーがescを押した場合や、外部入力をクリックした場合など)と、コールバックをすぐに終了して起動するための機能(たとえば、ユーザーがEnterキーを押した場合)があります。

searchBid.stop();
searchBid.finish(valueToPass);

1

単純なHTML / JSコードを探していましたが、見つかりませんでした。次に、を使用して以下のコードを記述しましたonkeyup="DelayedSubmission()"

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pt-br" lang="pt-br">
<head><title>Submit after typing finished</title>
<script language="javascript" type="text/javascript">
function DelayedSubmission() {
    var date = new Date();
    initial_time = date.getTime();
    if (typeof setInverval_Variable == 'undefined') {
            setInverval_Variable = setInterval(DelayedSubmission_Check, 50);
    } 
}
function DelayedSubmission_Check() {
    var date = new Date();
    check_time = date.getTime();
    var limit_ms=check_time-initial_time;
    if (limit_ms > 800) { //Change value in milliseconds
        alert("insert your function"); //Insert your function
        clearInterval(setInverval_Variable);
        delete setInverval_Variable;
    }
}

</script>
</head>
<body>

<input type="search" onkeyup="DelayedSubmission()" id="field_id" style="WIDTH: 100px; HEIGHT: 25px;" />

</body>
</html>

0

時計をリセットしたいだけなのに、なぜそんなに多くのことをするのですか?

var clockResetIndex = 0 ;
// this is the input we are tracking
var tarGetInput = $('input#username');

tarGetInput.on( 'keyup keypress paste' , ()=>{
    // reset any privious clock:
    if (clockResetIndex !== 0) clearTimeout(clockResetIndex);

    // set a new clock ( timeout )
    clockResetIndex = setTimeout(() => {
        // your code goes here :
        console.log( new Date() , tarGetInput.val())
    }, 1000);
});

WordPressで作業している場合は、このすべてのコードをjQueryブロック内にラップする必要があります。

jQuery(document).ready(($) => {
    /**
     * @name 'navSearch' 
     * @version 1.0
     * Created on: 2018-08-28 17:59:31
     * GMT+0530 (India Standard Time)
     * @author : ...
     * @description ....
     */
        var clockResetIndex = 0 ;
        // this is the input we are tracking
        var tarGetInput = $('input#username');

        tarGetInput.on( 'keyup keypress paste' , ()=>{
            // reset any privious clock:
            if (clockResetIndex !== 0) clearTimeout(clockResetIndex);

            // set a new clock ( timeout )
            clockResetIndex = setTimeout(() => {
                // your code goes here :
                console.log( new Date() , tarGetInput.val())
            }, 1000);
        });
});

jqueryを拡張し、このメソッドを複数の入力要素で使用する場合は、承認された回答が探している回答です。
insCode 2018


-1

私の考えでは、ユーザーはその入力に集中し続けると書き込みを停止します。このためには、ものを行う「ぼかし」と呼ばれる機能持っているように


4
違う!ぼかしは、特定の入力フィールドでフォーカスが失われたときのイベントです。私がする必要があるのは、イベントをトリガーしようとしているフィールドの下でキーボードが使用されていないときを判別することです。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.