web-dev-qa-db-ja.com

ユーザーがキーを押す代替に入力を終了したときにJavaScript関数を実行しますか?

ユーザーがテキストボックスに入力し終わったら、ajaxリクエストをトリガーします。ユーザーが文字を入力するたびに関数を実行したくないのは、Ajaxリクエストが大量に発生するためです。ただし、Enterボタンを押す必要もないようにします。

ユーザーが入力を終了した後にajaxリクエストを実行できるようにするための方法はありますか?

ここでjQueryを使う!デイブ

412
David Zorychta

それで、私はあなたがただしばらく止まることを意味するタイプ入力を終えることを推測するつもりです、5秒。したがって、それを念頭に置いて、ユーザーがキーを離したときにタイマーを開始し、ユーザーがキーを押したときにそれをクリアすることができます。問題の入力は#myInputになることにしました。

いくつかの仮定をしています...

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 second for example
var $input = $('#myInput');

//on keyup, start the countdown
$input.on('keyup', function () {
  clearTimeout(typingTimer);
  typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

//on keydown, clear the countdown 
$input.on('keydown', function () {
  clearTimeout(typingTimer);
});

//user is "finished typing," do something
function doneTyping () {
  //do something
}
596
Surreal Dreams

上で選んだ答えはうまくいきません。

TypingTimerは複数回設定されるため(キータイアップが速いタイプなどでトリガーされる前にキーを2回押す)、正しくクリアされません。

以下の解決策はこの問題を解決し、OPが要求した通りに終了してからX秒後に呼び出します。また、冗長なキーダウン機能も不要になりました。入力が空の場合に関数呼び出しが発生しないように、チェックも追加しました。

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms (5 seconds)

//on keyup, start the countdown
$('#myInput').keyup(function(){
    clearTimeout(typingTimer);
    if ($('#myInput').val()) {
        typingTimer = setTimeout(doneTyping, doneTypingInterval);
    }
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

そして、Vanilla JavaScriptソリューションの同じコード:

//setup before functions
let typingTimer;                //timer identifier
let doneTypingInterval = 5000;  //time in ms (5 seconds)
let myInput = document.getElementById('myInput');

//on keyup, start the countdown
myInput.addEventListener('keyup', () => {
    clearTimeout(typingTimer);
    if (myInput.value) {
        typingTimer = setTimeout(doneTyping, doneTypingInterval);
    }
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

このソリューションはES6を使用しますが、ここでは必要ありません。 letvarに、そしてarrow関数を通常の関数に置き換えてください。

349
going

これは、underscore.jsデバウンス関数を含む1行です。

$('#my-input-box').keyup(_.debounce(doSomething , 500));

これは基本的に、私がタイピングをやめてから500ミリ秒後にdoSomethingと言います。

詳細については、 http://underscorejs.org/#debounce

70
bit2pixel

はい、あなたはajaxリクエストを発生させるキーアップイベントごとに2秒のタイムアウトを設定することができます。 XHRメソッドを保存してその後のキー押下イベントで中止することもできます。これにより、バンド幅をさらに節約できます。これが私のオートコンプリートスクリプト用に書いたものです。

var timer;
var x;

$(".some-input").keyup(function () {
    if (x) { x.abort() } // If there is an existing XHR, abort it.
    clearTimeout(timer); // Clear the timer so we don't end up with dupes.
    timer = setTimeout(function() { // assign timer a new timeout 
        x = $.getJSON(...); // run ajax request and store in x variable (so we can cancel)
    }, 2000); // 2000ms delay, Tweak for faster/slower
});

お役に立てれば、

マルコ

40
Marko
var timer;
var timeout = 1000;

$('#in').keyup(function(){
    clearTimeout(timer);
    if ($('#in').val) {
        timer = setTimeout(function(){
            //do stuff here e.g ajax call etc....
             var v = $("#in").val();
             $("#out").html(v);
        }, timeout);
    }
});

ここに完全な例: http://jsfiddle.net/ZYXp4/8/

17
azzy81

私はSurreal Dreamの答えが好きですが、私の "doneTyping"関数はすべてのキー押下に対して起動することを発見しました。入力を止めるときに一度だけ起動するのではなく、関数は5回起動します。

問題は、javascriptのsetTimeout関数が、設定されている古いタイムアウトを上書きしたり強制終了したりしないように見えることですが、自分でやった場合はうまくいきます。 typingTimerが設定されている場合は、setTimeoutの直前にclearTimeout呼び出しを追加しただけです。下記参照:

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms, 5 second for example

//on keyup, start the countdown
$('#myInput').on("keyup", function(){
    if (typingTimer) clearTimeout(typingTimer);                 // Clear if already set     
    typingTimer = setTimeout(doneTyping, doneTypingInterval);
});

//on keydown, clear the countdown 
$('#myInput').on("keydown", function(){
    clearTimeout(typingTimer);
});

//user is "finished typing," do something
function doneTyping () {
    //do something
}

N.B.これをSurreal Dreamの回答へのコメントとして追加しただけでよいのですが、私は新規ユーザーなので十分な評判がありません。ごめんなさい!

10
Liam Flanagan

貼り付けなどの追加のケースを処理するために、受け入れられた回答を変更します。

//setup before functions
var typingTimer;                //timer identifier
var doneTypingInterval = 2000;  //time in ms, 2 second for example
var $input = $('#myInput');

// updated events 
$input.on('input propertychange paste', function () {
    clearTimeout(typingTimer);
    typingTimer = setTimeout(doneTyping, doneTypingInterval);      
});

//user is "finished typing," do something
function doneTyping () {
  //do something
}
8
Jecoms

トップ2の答えはどちらも私にはうまくいきません。だから、これが私の解決策です:

var timeout = null;

$('#myInput').keyup(function() {
    clearTimeout(timeout);

    timeout = setTimeout(function() {
        //do stuff here
    }, 500);
});
6
YSFKBDY

私はこの場合keyDownイベントが必要であるとは思わない(私が間違っているならなぜ私に言いなさい)。私の(jquery以外の)スクリプトでは、同様の解決策がそのように見えます。

var _timer, _timeOut = 2000; 



function _onKeyUp(e) {
    clearTimeout(_timer);
    if (e.keyCode == 13) {      // close on ENTER key
        _onCloseClick();
    } else {                    // send xhr requests
        _timer = window.setTimeout(function() {
            _onInputChange();
        }, _timeOut)
    }

}

これは私の最初のStack Overflowへの返信ですので、いつか誰かに役立つことを願っています:)

4
Rafal Pastuszak

ユーザーが入力を終了したときにコンピューターが推測できないため、厳密には「いいえ」と言えます。もちろん、キーを押すとタイマーが起動し、それ以降のキーを押すたびにタイマーをリセットできます。タイマーが期限切れになった場合、ユーザーはタイマーの時間内に入力していません - そのことを「入力完了」と呼ぶことができます。

ユーザーが入力中に一時停止をすると予想される場合は、ユーザーがいつ入力したのかを知る方法はありません。

(もちろん、いつデータが完成したのかわかりませんが)

4
sleske

inputイベントを使用すると、解決策がやや単純になると思います。

var typingTimer;
var doneTypingInterval = 500;

$("#myInput").on("input", function () {
    window.clearTimeout(typingTimer);
    typingTimer = window.setTimeout(doneTyping, doneTypingInterval);
});

function doneTyping () {
    // code here
}
2
Adrien Brunelat

ユーザーが入力を終了するのを待つための簡単なコードを考え出しました。

ステップ1.タイムアウトをnullに設定してから、ユーザーが入力しているときに現在のタイムアウトをクリアします。

ステップ2. keyupイベントがトリガーされる前に変数defineにタイムアウトをクリアします。

ステップ3.上記で宣言した変数にタイムアウトを定義します。

<input type="text" id="input" placeholder="please type" style="padding-left:20px;"/>
<div class="data"></div>

javaScriptコード

var textInput = document.getElementById('input');
var textdata = document.querySelector('.data');
// Init a timeout variable to be used below
var timefired = null;

// Listen for keystroke events
// Init a timeout variable to be used below
var timefired = null;// Listen for keystroke events
textInput.onkeyup = function (event) {
clearTimeout(timefired);
timefired = setTimeout(function () {
    textdata.innerHTML = 'Input Value:'+ textInput.value;
  }, 600);
};
2

私は自分のリストに検索を実装していて、それをajaxベースにする必要がありました。つまり、キーを変更するたびに、検索結果が更新されて表示されます。これにより、非常に多くのAjax呼び出しがサーバーに送信されますが、これは好ましくありません。

作業が終わった後、ユーザーが入力をやめたときにサーバーにpingを送信するというアプローチをとりました。

この解決策は私のために働きました:

$(document).ready(function() {
    $('#yourtextfield').keyup(function() {
        s = $('#yourtextfield').val();
        setTimeout(function() { 
            if($('#yourtextfield').val() == s){ // Check the value searched is the latest one or not. This will help in making the ajax call work when client stops writing.
                $.ajax({
                    type: "POST",
                    url: "yoururl",
                    data: 'search=' + s,
                    cache: false,
                    beforeSend: function() {
                       // loading image
                    },
                    success: function(data) {
                        // Your response will come here
                    }
                })
            }
        }, 1000); // 1 sec delay to check.
    }); // End of  keyup function
}); // End of document.ready

これを実装している間は、タイマーを使用する必要がないことに気付くでしょう。

2
Ata ul Mustafa

@goingの答えに同意する。私のために働いた別の同様の解決策は以下のものです。唯一の違いは、キーアップの代わりに.on( "input" ...)を使用していることです。これは入力の変化を捉えるだけです。 Ctrl、Shiftなどの他のキーは無視されます。

var typingTimer;                //timer identifier
var doneTypingInterval = 5000;  //time in ms (5 seconds)

//on input change, start the countdown

$('#myInput').on("input", function() {    
    clearTimeout(typingTimer);
    typingTimer = setTimeout(function(){
        // doSomething...
    }, doneTypingInterval);
});
2
Grace.io

Onblurイベントを使用して、テキストボックスがフォーカスを失ったことを検出できます。 https://developer.mozilla.org/en/DOM/element.onblur

ユーザーが大量のものを入力してから、テキストボックスにフォーカスを置いたままでそこに座ってしまう場合がある場合は、「入力を停止する」ことと同じではありません。

そのためには、setTimeoutをonclickイベントに結び付けることをお勧めします。そして、何もキーストロークを使わずにx時間後にユーザーが入力をやめたと仮定します。

1
Mike Ruhlin

次のdelay関数を宣言します。

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

そしてそれを使う:

let $filter = $('#item-filter');
$filter.on('keydown', function () {
    delay(function () {            
        console.log('this will hit, once user has not typed for 1 second');            
    }, 1000);
});    
1
Fabian Bigler

これは私が書いた簡単なJSコードです。

<!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>

テキストボックスにフォーカスがあることを検出したら、キーアップ時にタイムアウトチェックを行い、トリガーされるたびにリセットします。

タイムアウトが完了したら、ajaxリクエストを行います。

0
ocodo

私のニーズが単に奇妙なものであるかどうかわからないが、私はこれに似たものが必要であり、これが私が使用してしまったものである:

$('input.update').bind('sync', function() {
    clearTimeout($(this).data('timer'));            
    $.post($(this).attr('data-url'), {value: $(this).val()}, function(x) {
        if(x.success != true) {
            triggerError(x.message);    
        }
    }, 'json');
}).keyup(function() {
    clearTimeout($(this).data('timer'));
    var val = $.trim($(this).val());
    if(val) {
        var $this = $(this);
        var timer = setTimeout(function() {
            $this.trigger('sync');
        }, 2000);
        $(this).data('timer', timer);
    }
}).blur(function() {
    clearTimeout($(this).data('timer'));     
    $(this).trigger('sync');
});

これにより、私は自分のアプリケーションに次のような要素を含めることができます。

<input type="text" data-url="/controller/action/" class="update">

これは、ユーザーが「入力を終了」したとき(2秒間何もしない)または別のフィールドに移動したときに更新されます(要素からはみ出します)。

0

1ページに複数のタイマー

他のすべての答えは、1つのコントロール私の他の答え を含む)に対してのみ有効です。 1ページに複数のコントロール(ショッピングカートなど)がある場合、ユーザーが何かを入力した最後のコントロールのみが呼び出されます。私の場合、これは確かに望ましい動作ではありません - 各コントロールには独自のタイマーが必要です。

これを解決するには、単に関数にIDを渡し、次のコードのようにtimeoutHandles辞書を管理するだけです。

機能宣言:

var delayUserInput = (function () {
    var timeoutHandles = {};    
    return function (id, callback, ms) {        
        if (timeoutHandles[id]) {
            clearTimeout(timeoutHandles[id]);
        }

        timeoutHandles[id] = setTimeout(callback, ms);             
    };
})();

関数の使い方:

  delayUserInput('yourID', function () {
     //do some stuff
  }, 1000);
0
Fabian Bigler

Onfocusoutを使用しないのはなぜですか。

https://www.w3schools.com/jsreF/event_onfocusout.asp

フォームの場合は、送信ボタンをクリックするために常にすべての入力フィールドにフォーカスが置かれるため、onfocusoutイベントハンドラが呼び出されても入力が見逃されることはありません。

0
coffeeeee

ユーザーが入力を終了するまで待つ必要がある場合は、単純なこれを使用します。

$(document).on('change','#PageSize', function () {
    //Do something after new value in #PageSize       
});

Ajax呼び出しを使用した完全な例 - これは私のポケットベルのために働いています - リストごとのアイテムの数:

$(document).ready(function () {
    $(document).on('change','#PageSize', function (e) {
        e.preventDefault();
        var page = 1;
        var pagesize = $("#PageSize").val();
        var q = $("#q").val();
        $.ajax({
            url: '@Url.Action("IndexAjax", "Materials", new { Area = "TenantManage" })',
            data: { q: q, pagesize: pagesize, page: page },
            type: 'post',
            datatype: "json",
            success: function (data) {
                $('#tablecontainer').html(data);
               // toastr.success('Pager has been changed', "Success!");
            },
            error: function (jqXHR, exception) {
                ShowErrorMessage(jqXHR, exception);
            }
        });  
    });
});    
0
Miroslav Siska

特定の長さ(郵便番号フィールドなど)を探している場合

$("input").live("keyup", function( event ){
if(this.value.length == this.getAttribute('maxlength')) {
        //make ajax request here after.
    }
  });
0
Jason