1

I seem to have a timing problem with my jQuery change and click events. In my site I have it with an Ajax post instead of an alert, but it's easier to reproduce it using the alert. I have a simple HTML page using jQuery Version 1.7.1.

The scenario is editing the textbox and then directly clicking the button. The change event is always fired but if it contains a alert the click event is never called. If I cheat and put a timeout around the alert (you might have to play around a bit with the values there) the click event is called normally.

/** EDIT **/ If you set a breakpoint somewhere in the change event and wait for a few seconds the click event will aslo fail to fire.

<script type="text/javascript">
$(document).ready(function ()
{
    $("input[type=text]").change(function () {
        //alert('changed');

        $("#text").text('changed');

        setTimeout(function () {
            $("#text").text('changed timeout');
            alert('changed');
        }, 100);

    });

    $("input[type=submit]").click(function () {
        alert('clicked');
        $("#text").text('clicked');
    });
});
  </script>
  <div id="main">
    <div class="container">
        <input type="text" />
        <input type="submit" value="click me" />
        <div id="text" >bla</div>
    </div>
  </div>

My Ajax call that has the save behavoir is the following:

$.ajax({
        type: 'POST',
        url: postUrl,
        data: form.serialize(),
        beforeSend: function () {
            // display overlay for work in progress
        },
        success: function (result) {
            updateTableSuccess();
        },
        complete: function () {
            // hide overlay for work in progress
        },
        error: function (jqXHR) {
            if (jqXHR.responseText.length > 0) {
                showErrorMessage(jqXHR.responseText);
            }
        }
    });

The overlay is simply appending 2 divs to the body Tag.

/** Edit **/ It seems that the overlay is the real problem and causes the same behavoir as the alert and stops the click event from being fired.

showWorkInProgress = function (message, elementId)
{
    if ($("#overlay").length == 0)
    {
        $("<div id='overlay' class='ui-widget-overlay'></div>").appendTo("body");
    }

    if ($("#workInProgress").length == 0)
    {
        $("<div id='workInProgress'></div>").appendTo("body");
    }

    $("#workInProgress").html(message);
    if (elementId != null)
    {
        $("#workInProgress").center(elementId);
    }
    else
    {
        $("#workInProgress").center();
    }
    $("#overlay").show();
    $("#workInProgress").show();
};

Can anyone explain why jQuery behaves like this and how I could do this nicer without the setTimeout hack?

Thanks for any help =)

Nischo
  • 454
  • 6
  • 20
  • What exactly does the alert have to do with this? Alerts don't change the way code executes, it just blocks the browser until you click "OK". When the input loses focus, the change event happens, resulting in the alert box which blocks the browser, which prevents the submit button from being interacted with (i'm guessing). Do your debugging with console.log() or maybe even better, step through it line by line with a debugger. – Kevin B Jan 07 '13 at 15:46
  • If I debug and set a breakpoint on the $("#text").text('changed'); and wait a few seconds the click event also doesn't get fired. I'll edit the post for that.. – Nischo Jan 07 '13 at 16:04
  • Your code works just fine. http://jsfiddle.net/w9Thc/5/ Stop getting stuck in the alert. Get to the real problem. – Kevin B Jan 07 '13 at 16:07
  • Are you using `async: false` with your ajax request? – Kevin B Jan 07 '13 at 16:12
  • No, it's the default value, so true. – Nischo Jan 07 '13 at 16:14

3 Answers3

1

Nischo, I cannot replicate the blocking when inserting your AJAX code into the change function. If you are looking to block the AJAX if executing when the click is fired on the submit look here.

jQuery - How can I temporarily disable the onclick event listener after the event has been fired?

Best of luck.


After your explanation I do see what you are referring to, since the change event requires lost focus to fire your click function is overridden as a result of the blocking caused by the lost focus being your click.

You could use the timeOut as you stated or you could refactor to a keydown method on your text input. See below:

$(document).ready(function () 
{
   $("input[type=submit]").click(function () {
      $("#text").text('clicked');
   });

   $("input[type=text]").keydown(function () {
      alert('changed');
      $("#text").text('changed');
   });
});

Fiddle: http://jsfiddle.net/9WXBe/2/


Nischo,

After taking your code and placing it in jsFiddle I do not see any problems with the change event being fired. Even with an alert in the code.

$("input[type=text]").change() will not fire until the textbox loses focus, other elements such as select, radio will perform this action immediately after a selection or change is made.

Here is the fiddle: http://jsfiddle.net/w9Thc/1/

Community
  • 1
  • 1
zombiehugs
  • 717
  • 3
  • 10
  • I'm sorry, maybe I wasn't clear enough. The problem is not the change event but the click event that doesn't get fired anymore. The change event always gets fired normally. – Nischo Jan 07 '13 at 16:02
  • Updated solution for you above to reflect this issue, use keydown() – zombiehugs Jan 07 '13 at 16:20
  • Thanks, I'd preferr not using keydown because in the ajax call I get data from the database and it probably wouldn't have the best performance like this or I would start 6 requests and abort them again instantly. What I still don't get is why it would not block the event if it only sets a text on the page but will block it after about 10ms. – Nischo Jan 07 '13 at 16:25
  • True, I forgot about the whole AJAX call. So you are planning on making an AJAX call when the the person removes focus from the box, the problem is they generally click submit first. – zombiehugs Jan 07 '13 at 16:46
  • Yep, exactly. My best case scenario would be to somehow know if the button was clicked when the changed event is called and if it was, don't even do the ajax but only the click event. But I'd be happy with aborting the call later aswell =) – Nischo Jan 07 '13 at 16:53
  • Nischo, using your code and applying the AJAX in the code on the Change event I do not see any blocking happening on the Click event for submit. Check my solution, I've added a link that might help you. If you create an object for you AJAX you should also be able to cancel it in the click for the submit button. – zombiehugs Jan 07 '13 at 17:10
  • Thanks for you help, it seems that the problem is my overlay during the ajax call which results the same behavoir as the alert, blocking the click from being fired. I'll update my post with the info =) – Nischo Jan 08 '13 at 06:56
1

Just for a short answer if anyone else has the same problem: The problem really is the overlay which is blocking the whole page, which causes the same behavoir as the alert.

My explanation for it is that the change event gets fired, blocks the UI and the click event can't be fired anymore because of that as suggested by https://stackoverflow.com/users/1861269/john-gerdsen.

The only solution I found for this problem was to make the overlay smaller and block only the part that really needs to be blocked. The timeout worked aswell but not in every case because every machine had different performance.

This might help anyone trying which is also fighting with the overlay problem: HTML "overlay" which allows clicks to fall through to elements behind it

Community
  • 1
  • 1
Nischo
  • 454
  • 6
  • 20
0

Problem only seems to occur with Firefox. Other browsers do not appear to have the problem. I fixed my problem by re-writing things to not use the text field change event. Unfortunately I have another piece of code where I cannot do that. Change event does seem to block the UI, because I find no events on the "click" button of any kind fire.