そこで、現在のプロジェクトでもう 1 つ小さな JavaScript の問題があります。JS イベントが期待どおりの順序で起動されません。
サーバー上で計算を行う AJAX 呼び出しを起動する onBlur イベントを含むテキスト フィールドがあるとします (JSON で .NET 3.5 の WebServices を使用しています)。そのコールバック メソッドは、テキスト フィールドでいっぱいのページに計算結果を入力します。
別の計算を開始する onClick イベントを持つボタンもありますが、onClick イベントの結果が有効になる前に、テキスト フィールドの onBlur イベントを終了する必要があります。
次の状況まで、かなりうまく機能する単純なミューテックスを配置しています。ユーザーがテキストフィールドの1つの値を変更しましたが、まだそこから離れていないため、フォーカスはテキストフィールドに残っています。テキスト フィールドにフォーカスがある間に、onClick イベントを持つボタンをクリックします。 多くの場合、ブラウザ (この場合は IE7) は、テキスト フィールドの onBlur イベントの前に、ボタンの onClick イベントを発生させます。
これは大混乱を引き起こし、発生するイベントの順序を強制する方法がわかりません。私の小さなミューテックスは次のように機能します。いずれかのイベントが発生すると、「コールバックを待機する」ことを意味するフラグを設定します。発生する後続のイベントは、何かを行う前にフラグをチェックします。コールバックで、フラグを false にリセットします。
それで、何かアイデアはありますか?私はほとんどすべての Web サービス呼び出しを同期させたいと思っていますが、それを行う簡単な方法があるかどうかはわかりません。
私が試したこと、または知っておくべきその他のこと: - テキスト フィールドの onBlur のボタンを無効にする - それらの onClick は、無効になる前に起動します - これは、テキスト フィールドを編集してすぐにボタン。ユーザーがボタンをクリックする前に空のスペースをクリックしてテキスト フィールドの onBlur を起動すると、すべてが完全に機能します。
編集:
いくつかのコメントとさらにテストした後、私ができるようにしたいことは次のとおりです。
テキスト フィールドの onBlur で、ボタンを無効にして、その onClick イベントが発生しないようにします。ただし、これをコーディングすると、onBlur イベントが発生し、ボタンが無効になっていることがわかりますが、onClick イベントはまだ発生しています。
ここにいくつかのサンプルコードがあります。 onClick イベントが発生する場合と発生しない場合があります。 setTimeout を 500ms 程度に上げると、常に防止されるようです。たぶんこれはオプションです...
<html>
<head>
<script type="text/javascript">
var onClickFlag = false;
function whatHappensOnFocus(el) {
log('whatHappensOnFocus(): TextField focused.');
onClickFlag = false;
log('whatHappensOnFocus(): Set onClickFlag = false');
}
function whatHappensOnBlur(el) {
log('whatHappensOnBlur(): TextField blurred.');
document.getElementById('theButton').disabled = true;
log('whatHappensOnBlur(): Disabled the Button');
setTimeout(function() { someTestFieldFunction(); log('whatHappensOnBlur(): OnBlur callback called: someTestFieldFunction()'); }, 50);
log ('whatHappensOnBlur(): setTimeout for someTestFieldFunction() for 50ms');
}
function log(msg) {
document.getElementById('log').value += ('[' + (new Date().getTime()).toString() + '] ' + msg + '\n');
}
function someTestFieldFunction() {
log('someTestFieldFunction(): Inside someTestFieldFunction()');
log('someTestFieldFunction(): Test: onClickFlag = ' + onClickFlag);
//alert('you blurred the text field.');
//alert('onClickFlag = ' + onClickFlag);
setTimeout(enableButton, 50);
log('someTestFieldFunction(): setTimeout for enableButton()');
}
function enableButton() {
document.getElementById('theButton').disabled = false;
log('enableButton(): Button re-enabled');
//onClickFlag = false;
}
function whatHappensOnClick(el) {
log('whatHappensOnClick(): the Button onClick fired');
someFunction();
log('whatHappensOnClick(): someFunction() called');
}
function whatHappensOnMouseDown(el) {
log('whatHappensOnMouseDown(): inside whatHappensOnMouseDown()');
onClickFlag = true;
log("whatHappensOnMouseDown(): set onClickFlag = true");
}
function someFunction() {
log('someFunction(): inside someFunction()');
log('someFunction(): You have successfully clicked the button');
//alert("you clicked me! this shouldn't happen!")
}
</script>
</head>
<body>
<form id="testform">
<input type="text" size="10" onfocus="whatHappensOnFocus(this);" onblur="whatHappensOnBlur(this);" />
<br />
<br />
<input id="theButton" type="button" onmousedown="whatHappensOnMouseDown(this);" onmouseout="onClickFlag = false;" value="calculate" onclick="whatHappensOnClick(this);" />
<br />
<br />
<textarea rows="15" cols="100" id="log" style="overflow: scroll"></textarea>
<input type="reset" value="clear" />
</form>
</body>
</html>
アップデート:
問題の一部を反映するために投稿したコードを更新したので、これをどのようにテストしたかがわかります。テキスト フィールドにフォーカスを置いてボタンをクリックすると、テキスト フィールドの onBlur イベントの前にボタンの onMouseDown イベントが発生します。このため、ボタンをクリックしようとしたことがわかるようにフラグを設定できます。次に、テキスト フィールドの onBlur イベントによって起動された AJAX 呼び出しの onSuccess コールバック イベントで、ボタン フラグが設定されているかどうかを確認し (したがって、ボタンをクリックしようとしたことがわかります)、そのイベントを起動します (他のすべてを無効にして、ボタンがクリックできるようにします)。完了)。この動作が必要なフォーム上のボタンはわずかしかないため、現時点ではこのソリューションで十分だと思います。