views:

565

answers:

4

I am trying to delay the default event or events in a jQuery script. The context is that I want to display a message to users when they perform certain actions (click primarily) for a few seconds before the default action fires.

Pseudo-code: - User clicks link/button/element - User gets a popup message stating 'You are leaving site' - Message remains on screen for X milliseconds - Default action (can be other than href link too) fires

So far, my attempts look like this:

$(document).ready(function() {
    var orgE = $("a").click();
    $("a").click(function(event) {
        var orgEvent = event;
        event.preventDefault();
        // Do stuff
        doStuff(this);

        setTimeout(function() {
            // Hide message
            hideMessage();
            $(this).trigger(orgEvent);
        }, 1000);
    });
});

Of course, this doesn't work as expected, but may show what I'm trying to do.

I am unable to use plugins as ths is a hosted environment with no online access.

Any ideas?

A: 

This might work:

$(document).ready(function() {
  $("a").click(function(event) {
    event.preventDefault();
    doStuff(this);

    setTimeout(function() {
      hideMessage();
      $(this).click();
    }, 1000);
  });
});

Note: totally untested

JimNeath
Wouldn't this fire the same click handler again, including the `event.preventDefault`?
DLH
It wont work as the this context will be the window and not the anchor
redsquare
need to take a reference to the anchor and use that inside the setTimeout. However yes it would result in a infinite loop. You would need to unbind the click event in order for it not to run.
redsquare
My bad. Late nights don't make for a healthy mind :P
JimNeath
A: 

I would probably do something like this.

$("a").click(function(event) {
   event.preventDefault();
   doStuff(this);
   var url = $(this).attr("href");

   setTimeout(function() {
      hideMessage();
      window.location = url;
   }, 1000);
});

I'm not sure if url can be seen from inside the timed function. If not, you may need to declare it outside the click handler.

Edit: If you need to trigger the event from the timed function, you could use something similar to what karim79 suggested, although I'd make a few changes.

$(document).ready(function() {
  var slept = false;
  $("a").click(function(event) {
    if(!slept) {
        event.preventDefault();
        doStuff(this);

        var $element = $(this);
        // allows us to access this object from inside the function

        setTimeout(function() {
          hideMessage();
          slept = true;
          $element.click(); //triggers the click event with slept = true
        }, 1000);
        // if we triggered the click event here, it would loop through
        // this function recursively until slept was false. we don't want that.
    } else {
        slept = false; //re-initialize
    }
  });
});

Edit: After some testing and research, I'm not sure that it's actually possible to trigger the original click event of an <a> element. It appears to be possible for any element other than <a>.

DLH
It can read the var url
redsquare
The problem with this approach is that I do not know if the original action is to go to a URL. It may simply be another javascript function that has nothing to do with navigation at all.
Bjørn Furuknap
A: 

Something like this should do the trick. Add a new class (presumably with a more sensible name than the one I've chosen) to all the links you want to be affected. Remove that class when you've shown your popup, so when you call .click() again your code will no longer run, and the default behavior will occur.

$("a").addClass("fancy-schmancy-popup-thing-not-yet-shown").click(function() {
    if ($(this).hasClass("fancy-schmancy-popup-thing-not-yet-shown"))
        return true;

    doStuff();
    $(this).removeClass("fancy-schmancy-popup-thing-not-yet-shown");

    var link = this;
    setTimeout(function() {
      hideMessage();
      $(link).click().addClass("fancy-schmancy-popup-thing-not-yet-shown";
    }, 1000);

    return false;
});
VoteyDisciple
I'm still not seeing how this will preserve the original event in any way. Am I missiong something?
Bjørn Furuknap
The later call to `$(link).click()` will behave as though the user just clicked the link in question. Your event handler for that click event will of course run again, but this time the link will no longer carry that class, so your event handler will just return true.Whenever an event handler returns true, the browser will continue performing other actions associated with the event, including the original (default) behavior (e.g., going to a new page).
VoteyDisciple
A: 

Probably the best way to do this is to use unbind. Something like:

$(document).ready(function() {
    $("a").click(function(event) {
        event.preventDefault();
        // Do stuff
        this.unbind(event).click();
    });
})
scruffian