2

I have a document.onclick function that I would like to have a delay. I can't seem to get the syntax right.

my original code is

<script type="text/javascript">
document.onclick=check;

function check(e){do something}

I tried the below, but that code is incorrect, the function did not execute and nothing happened.

<script type="text/javascript">
document.onclick=setTimeout("check", 1000);

function check(e){do something}

I tried the next set, the function got executed, but no delay.

<script type="text/javascript">
setTimeout(document.onclick=check, 1000);

function check(e){do something}

what is the correct syntax for this code.

TIA

Edit:

The solutions were all good, my problem was that I use the function check to obtain the id of the element being clicked on. But after the delay, there is no "memory" of what was being clicked on, so the rest of the function does not get executed. Jimr wrote the short code to preserve clicked event.

The code that is working (not work in IE6)

document.onclick = makeDelayedHandler( check, 1000 );
// Delay execution of event handler function "f" by "time" ms.
function makeDelayedHandler( f, time)
{
  return function( e )
  {
    var ev = e || window.event;
    setTimeout( function()
    {
      f( ev );
    }, time );        
  };
}


function check(e){ 
var click = (e && e.target) || (event && event.srcElement);  
.
.
.

Thank you all.

update: kennebec's solution works for IE6.

Jamex
  • 732
  • 3
  • 9
  • 17

5 Answers5

4

Something like:

document.onclick = function () {
  setTimeout(check, 1000);
};
  • The setTimeout method doesn't return a function, it returns a number, which is the timer Id that you can use in case you want to cancel the timer before it fires (with clearTimeout)
  • You don't need to use strings as the first argument, use a function reference.
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • Hi, that does not work, the function does not get executed, nothing happened. Your function needs to have the brackets () after check for it to execute, but still no time delay. – Jamex Jun 15 '10 at 18:47
  • 2
    @Jamex: No, if you execute the function, the return value will be passed as argument of the `setTimeout`, check [this example](http://jsbin.com/eyifi3/2). – Christian C. Salvadó Jun 15 '10 at 18:55
  • @Jamex, that's exactly what it does, when the click handler is executed, `check` will be invoked one *second later*, did you saw my [example](http://jsbin.com/eyifi3/2)? Is the `check` function available in the scope where you are using this snippet? Maybe you could post more code to see where the problem is... – Christian C. Salvadó Jun 15 '10 at 19:15
  • @CMS, Sorry, but your function does work (after I put some alert statements). The problem is that I use the function check to obtain the id of the element being clicked on. But after the delay, there is no "memory" of what was being clicked on, so the rest of the function does not get executed. – Jamex Jun 15 '10 at 19:34
  • @Jamex, please post how do you get the *id* of the element, I suspect you may be having problems with the `this` value... – Christian C. Salvadó Jun 15 '10 at 22:21
  • …or the Event interface is no longer available as soon as `check` (or something) is called (and not saved somewhere else). – Marcel Korpel Jun 16 '10 at 01:54
2

You can make a generic function that will make a delayed event handler. E.g.

// Delay execution of event handler function "f" by "time" ms.
function makeDelayedHandler( f, time)
{
  return function( e )
  {
    var ev = e || window.event;
    setTimeout( function()
    {
      f( ev );
    }, time );        
  };
}

function check( e )
{
  // Your original handler
}

document.onclick = makeDelayedHandler( check, 1000 );
jimr
  • 11,080
  • 1
  • 33
  • 32
  • Thank you jimr, this works very well. I understand this code a little. – Jamex Jun 15 '10 at 21:22
  • You should append `var e = e || window.event;` to that, otherwise it won't work in IE. And I suspect you get into troubles with closures this way, I'm not sure, it's *way* too late here. – Marcel Korpel Jun 16 '10 at 01:48
  • Updated. I don't think a memory leak happens in IE - there's no circular reference being made. The leaks happen when you assign a closure to a DOM element property that closes over a reference to that element. – jimr Jun 16 '10 at 03:26
  • /Marcel, you were right, the original function did not work with IE6 (not tested with other IEs). The current function does not work with IE6 either. – Jamex Jun 16 '10 at 04:26
  • About closures: indeed, but not only when things are attached to DOM elements, IIRC; I thought that you can also get memory leaks when you refer to a variable of an outer function inside a closure (like `ev` in this case), but I'm not sure. – Marcel Korpel Jun 16 '10 at 11:32
1
window.twotimer=function(e){
    if(arguments[1]!= 'timer'){
        // If the 'timer' argument was not passed,
        // the function was called from the event,
        // so call it again with a timer

        e= window.event || e;
        var target= e.target || e.srcElement;
        setTimeout(function(){return twotimer(target,'timer')},1000);

        if(e.stopPropagation) e.stopPropagation();
        e.cancelBubble=true;
        return false;
    }
    // if you get to this point, e is the element node clicked
    // a second ago-
    // put your function body here, using e for the element clicked
    alert(e.nodeName+' id='+ e.getAttribute('id')+'\nwas clicked a second ago');
}
document.onclick= twotimer;
kennebec
  • 102,654
  • 32
  • 106
  • 127
  • Thank you kennebec, it works in IE6. Although I don't know how does it work. – Jamex Jun 16 '10 at 04:50
  • @Jamex: Ah, I see: in IE, I think `window.event` gets reset after the event handler is called, so `srcElement` is no longer available. – Marcel Korpel Jun 16 '10 at 11:35
0
document.onclick = function() {
    setTimeout("check()",1000);
};

function check() {
    alert("I'm baaaaaack!");
}

That should work...

roryhewitt
  • 4,097
  • 3
  • 27
  • 33
  • Sorry, you function does work. The problem is that I use the function check to obtain the id of the element being clicked on. But after the delay, there is no "memory" of what was being clicked on, so the rest of the function does not get executed. – Jamex Jun 15 '10 at 19:39
  • Jamex, Could you retrieve the clicked element at the beginning of the onclick function (before the call to setTimeout) and pass that element's ID to check()? – roryhewitt Jun 16 '10 at 21:42
0

You need to call window.setTimeout().

Also, window.setTimeout() takes a function reference so no need for quotes around check. Adding quotes does an eval() on the quoted string, which is slow and unnecessary.

This should work

document.onclick = function(e) {
    function check() {
        return function() {
            //do something
        }
    }
    window.setTimeout(check, 1000);
}
jasongetsdown
  • 1,295
  • 1
  • 17
  • 22
  • Thanks Jason, I think your function does work, except that my check function is designed to get the id of the element that was being clicked on. But after the delay, there is no memory of what was being clicked on, so the rest of the codes don't get executed, that is why it appeared as if the check function did not get called. – Jamex Jun 15 '10 at 19:43
  • The clicked element is available to `check()` in `e.target`. That's why I have `check()` returning a function, it creates a closure that preserves the value of `e` (without passing `e` as an argument, which you can't do) until `window.setTimeout()` evaluates `check` and returns. – jasongetsdown Jun 15 '10 at 19:54
  • Hi Jason, thanks. my check function is very long and I spent 2 days trying to get it to work. I don't think I know enough to start wrapping your code around what I have. Is there a way that I can introduce a delay between 2 lines of codes without using the settimeout function, the settimeout function requires a function call in its arguments. I am looking for something like "delay(1000);" – Jamex Jun 15 '10 at 20:09
  • In short, no. `setTimeout` is the correct way to do this. If your `check()` function takes only the event object as its argument, as it does in your examples, then you should be able to simply paste the body of the function in place of `//do something`. (note that I made a slight edit to my example). – jasongetsdown Jun 15 '10 at 20:37
  • I think you're getting confused by the fact that you can't pass an argument with your function reference in `window.setTimeout`. You don't have to if you use my example. `e` will be available to `check()` when it runs because it was defined in a scope where `e` was available. This is called "closure." – jasongetsdown Jun 15 '10 at 20:41
  • Hi Jason, thanks for your effort, I tried your suggestion, but it does not work as is. I like the approach, I will look more into it. – Jamex Jun 15 '10 at 20:43