Javascript-Ereignisse nicht auslösen in der erwarteten Reihenfolge
So, ich habe noch ein anderes kleines JavaScript Problem mit meinem aktuellen Projekt: JS Ereignisse sind nicht feuern in der Reihenfolge, wie ich es erwartet habe.
Sagen wir, ich habe ein Textfeld mit einem onBlur-Ereignis, das ausgelöst wird ein AJAX-Aufruf, erfolgt eine Berechnung auf dem server (ich bin mit .NET 3.5 Web Services mit JSON). Seine callback-Methode füllt eine Seite voller text-Felder mit den Ergebnissen aus der Berechnung.
Ich habe auch eine Schaltfläche mit einem onClick-Ereignis initiiert, die eine andere Berechnung, aber es beruht auf dem Abschluss des Textfeldes onBlur-Ereignis(s), bevor die Ergebnisse der onClick-Ereignis gültig wird.
Habe ich eine einfache mutex-die funktioniert auch Recht gut, bis die folgende situation: Der Benutzer ändert einen Wert in einem der Textfelder hat aber noch nicht verlassen, so konzentrieren sich immer noch auf das text-Feld. Während das Textfeld den Fokus hat, werden Sie auf eine Schaltfläche klicken, die hat ein onClick event. Mehr als oft nicht, der browser (IE7 in diesem Fall) feuert das onClick-Ereignis der Schaltfläche, BEVOR Sie das onBlur-Ereignis für das Textfeld!
Dies bewirkt, dass einige Chaos, und ich habe keine Ahnung, wie das durchzusetzen, um die Reihenfolge der Ereignisse ausgelöst wird. Meine kleine mutex funktioniert wie folgt: wenn die Ereignisse ausgelöst werden, setze ich ein flag, das bedeutet "warten auf den Rückruf." Alle nachfolgenden Ereignisse, Feuer, überprüfen Sie die fahne, bevor etwas zu tun. In der callback-ein zurücksetzen der flag auf "false".
So, irgendwelche Ideen? Ich denke, ich möchte fast alle web-service-Aufrufe synchron, aber ich weiß nicht, ob es eine einfache Möglichkeit, das zu tun.
Andere Dinge, die ich versucht habe, oder Dinge, die Sie wissen sollten:
- Deaktivieren Sie die Schaltflächen in der onBlur der Textfelder-Ihre onClicks noch Feuer, bevor Sie deaktiviert
- Denken Sie daran, dies geschieht nur, wenn der Bearbeitung ein Textfeld und sofort Klick auf eine Schaltfläche. Wenn der Benutzer klickt auf den leeren Raum, um das Feuer der onBlur-text-Feld, bevor Sie auf die Schaltfläche, es funktioniert alles perfekt.
EDIT:
Nachdem Sie einige Kommentare und mehr Tests hier ist, was ich möchte in der Lage sein zu tun:
In der onBlur des Textfeldes ich den deaktivieren-button, so dass Sie die onClick-Ereignis nicht ausgelöst. Allerdings, wenn ich code auf, das onBlur-Ereignis ausgelöst wird, ich kann sehen, dass die Schaltfläche immer deaktiviert, aber die onClick-Ereignis ist immer noch feuern.
Hier einige Beispiel-code. Manchmal das onClick-Ereignis passiert, und manchmal nicht. Wenn Sie die setTimeout-500 MS oder so, es scheint immer zu verhindern. Vielleicht ist das eine option...
<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>
UPDATE:
Ich aktualisiert, der code, den ich gepostet reflektieren einige der Problem, so dass Sie sehen können, wie ich diese getestet. Wenn Sie den Fokus auf ein Textfeld und klicken Sie auf eine Schaltfläche, wird das onMouseDown-Ereignis der Schaltfläche feuert, BEVOR das onBlur-Ereignis des Textfelds. Da kann ich ein flag setzen, so dass ich weiß, Sie haben versucht, auf die Schaltfläche klicken. Dann in der onSuccess-callback-event des AJAX-Aufruf ausgelöst durch das onBlur-Ereignis für das Textfeld, kann ich sehen, wenn der button gesetzt ist (also ich weiß, dass Sie versucht darauf zu klicken) und das Feuer, das Ereignis (das deaktivieren alles andere, so dass es abgeschlossen werden kann). Es gibt nur ein paar Schaltflächen auf dem Formular, muss dieses Verhalten, also ich denke, diese Lösung reicht für jetzt.
- Habe gerade einen kurzen test, und das blur-Ereignis feuert immer zuerst bei mir im IE7.
- Wirklich? Ich glaube, Sie... lassen Sie mich versuchen, ein quick-test als auch...
- Ok, du hast Recht. Ich habe bearbeitet die Frage, denn ich habe immer noch komische Verhalten.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sind Sie mit
AddEventListener
auf die Ereignisse einrichten? Wenn ja, was sind Sie vorbei in für den Dritten parameter?Dieser hilfreich sein kann:
http://www.quirksmode.org/js/events_order.html
Was mit js zu bewirken, dass die textbox den Fokus verliert, nachdem er beendet hat, zu tun, was es braucht?
Ich bezweifle, dass die Reihenfolge der Ereignisse sind die Ursache des Problems. Ich habe gerade versucht den folgenden code im IE7, IE8 und Google Chrome und die Reihenfolge der Ereignisse ist immer Unschärfe dann klicken.
Wenn ich Sie richtig, Sie tun einige Anrufe, die andere fordert, abgeschlossen vor. Dies scheint nicht, ein sehr guter Ansatz, und Sie wird entweder mal bugs oder die hohe Komplexität des code mit diesem Ansatz.
Bitte versuchen zu erklären, was Sie tun (aus funktionaler Sicht) und versuchen, sich alternative Wege, es zu tun, anstatt zu versuchen, herauszufinden, einen komplexen technischen Ansatz.
Ich nehme an, Ihr click-Ereignis stützt sich auf das Ergebnis der blur-event. In diesem Fall denke ich, das beste, was zu tun ist, ist die Schaltfläche deaktiviert werden (oder verstecken), und dann aktivieren Sie es, wenn Ihr onblur-Anfrage ist fertig.
Und die pseudo-Javascript...
Am einfachsten (und wahrscheinlich auch der SCHLECHTESTE und mit Abstand), wäre das Programm warten eine gewisse Zeit, bevor Sie fortfahren, was Sie wollte, es zu tun in den ersten Platz, auf diese Weise können Sie Steuern die Reihenfolge der Rückrufe.
Als ich sagte, dies ist wahrscheinlich der schlechteste Weg, es zu tun, aber es ist die einzige, die ich denken kann. Hier ist, was es Aussehen sollte :
Diese Weise, wird Ihre callback-Funktion onBlur würde passieren immer zuerst.
Das problem mit einem festen timeout von 50ms ist, dass Sie sich auf die Zeit um das problem zu lösen. Was ist, wenn der computer langsam ist für einige Grund, oder bist du auf einem langsamen Netbook oder einen alten computer oder eine alte browser-oder mobile? Vielleicht solltest du mit setInterval statt setTimer und warten, bis Sie überprüft haben, dass die Deaktivierung tatsächlich passiert ist.