views:

77

answers:

3

I'm using a product called DHTMLXGrid, which is a JS library for creating spreadsheet-like tables on a web page.

When I edit a cell, and then click outside the cell, an event is fired (they call it onCellEdit) and I do stuff to handle that event - an AJAX call to save the cell data to the DB.

But if the user edits a cell and clicks a button outside the grid that triggers some other JavaScript, the onCellEdit handler doesn't get chance to run before the new JS code runs. Without going into the details, this messes things up.

So I have the "Grid code" and the "Button code" and I want the Button code to wait till the Grid code is done.

So I tried inserting a silly sleep() method at the start of the Button code run. My erroneous thinking was that this would give the Grid code a chance to run. But that assumes multi-threading which of course we don't have. The result was that all JS code execution was held up, and my Button code still got executed before the Grid code.

So the general problem is that clicking a button removes focus from the previously selected element. Both the click and the change/blur are events. I want the blur event to be handled before the click event. The opposite seems to happen. I'm assuming that in pure JS it would work this way (I haven't tried it), but this is a complex library that does it's own thing.

Bottom line - is there a way I can asynchronously pause my Button code to allow my Grid code to complete, then proceed with the Button code?

Thanks,

Paul

A: 

Set a small (but not too small) timeout in your button handler, like this:

setTimeout(function {
    //Button handler
}, 100);    //100 means this will execute after 100 milliseconds.

If the grid code starts running befoer the timer "rings", the function will only be executed after the grid code finishes (because Javascript is single threaded). You should choose a timeout value large enough to let the grid code start running before it rings.

SLaks
Thats pretty nondeterministic. It may work in one environment and not in another.
Frank Schwieterman
@Frank Schwieterman: no, this behaviour is consistent across all browsers in the wild, and is in the process of being standardised through the W3C.
NickFitz
Thanks very much - this approach did the trick (that is to say it's worked everytime so far...) I had actually tried setTimeout but had evidently not got it right. At any rate, not withstanding comments about the "cross your fingers" nature of this stuff, it's a ton better than what I had.Thanks again.
Then you should accept this answer.
SLaks
Whats nondeterministic is the timing and how it relates to other things going on. For instance, what if the user double clicks and that second click comes in before the timeout. Weird race conditions can happen. I did not mean to imply setTimeout is inconsistently implemented. You're probably best off setting a timeout of 0 going with this approach.
Frank Schwieterman
+1  A: 

It all sounds like a bit of a mish-mash :-(

You could try setting a timeout at the start of your click handler:

function myClickHandler(event) {
    // make sure we have the stuff we need from the event object
    var something = event.someProperty;
    var x = event.x;
    setTimeout(function() {
        doWonderfulThings(something, x);
    }, 1);
}

Despite the 1 millisecond delay, all browsers will wait at least ten milliseconds before running the inner function, and the blur event should get processed during that time. Of course if the processing for the blur event takes a long time - say, more than about a twentieth of a second - then the user will perceive the delay in the response from the button, which could become an issue...

EDIT: I've changed from 0ms to 1ms, as I've just remembered that some extremely old version of Opera had a problem with 0 - unlikely to be an issue, but you can't be too careful

NickFitz
Does the downvoter want to offer an explanation? This may be a pretty hackish solution to what sounds like an unfortunate clashing of scripts, but it will work as I describe.
NickFitz
+1 seems like a viable solution to me too
JustLoren
A: 

I don't think that you're ultimately going to be able to rely on any definite series of event loop processing. What might work a little bit more robustly than adding simple cross-your-fingers timeout delays would be to have the direct event handlers for the "onCellEdit" and your control buttons all just add command blocks (probably just callable closures) to distinct work queues. Give your page a 100ms (or 50ms or whatever) interval timer that runs code to pull work off those queues. Have that code prioritize the work however you want - cell changes first, button X next, button Y last, or whatever. Of course, this approach would still be vulnerable to the condition wherein your interval timer event sneaks in between the "blur" from the table cell and the "mousedown" (or "click") on your button.

Pointy