38

I would like to execute some function when the user presses for 2 seconds on a div.

Is it possible ?

Here is my code to detect the click on the div

$('div').mousedown(function() {

});
Steffi
  • 6,835
  • 25
  • 78
  • 123

13 Answers13

38

Add a throttle that only allows the click to happen after 2 seconds of mousedown.

var timer;
$('div').on("mousedown",function(){
    timer = setTimeout(function(){
        alert("WORKY");
    },2*1000);
}).on("mouseup mouseleave",function(){
    clearTimeout(timer);
});

Edit: I added mouseleave too since if the mouse leaves the element and then triggers mouseup, it won't stop the timer.

Kevin B
  • 94,570
  • 16
  • 163
  • 180
  • Your answer is pretty cool but didn't work on mobile for me. This worked for me: https://github.com/vaidik/jquery-longpress/blob/32718e9afc22ba98894db206455f1fa980f52b89/jquery.longpress.js – Ryan Apr 22 '19 at 18:03
  • @Does this work with a saparate single click too ? – Hunt Jan 20 '22 at 11:04
  • @Hunt not sure I understand – Kevin B Jan 20 '22 at 15:02
31

Just watch both mousedown and mouseup and calculate the difference. Here's an example.

(function() { 

    // how many milliseconds is a long press?
    var longpress = 3000;
    // holds the start time
    var start;

    jQuery( "#pressme" ).on( 'mousedown', function( e ) {
        start = new Date().getTime();
    } );

    jQuery( "#pressme" ).on( 'mouseleave', function( e ) {
        start = 0;
    } );

    jQuery( "#pressme" ).on( 'mouseup', function( e ) {
        if ( new Date().getTime() >= ( start + longpress )  ) {
           alert('long press!');   
        } else {
           alert('short press!');   
        }
    } );

}());
buley
  • 28,032
  • 17
  • 85
  • 106
  • perfect ! I love it. Exactly what I want. – Steffi Jan 29 '13 at 16:05
  • This code wouldn't work for multiple
    s or multiple clicks, as the variable *start* is global, and never cleared.
    – Mathieu Rodic Jan 29 '13 at 16:06
  • 2
    Creadiff, note the immediately invoked anonymous function wrapper. There's no global leakage in this code. – buley Jan 29 '13 at 16:07
  • I tried to do your code on a href="/page", it works but after the alert I'm redirecting to "/page". Even with a `e.preventDefault()` – Steffi Jan 29 '13 at 16:19
  • Hmm, `preventDefault` should do it (also might be worth throwing a `stopPropigation` in there). Are you event binding to the `anchor` element itself or a div/button around it? Possible the event is bubbling up to your listener and has already fires the location update. – buley Jan 29 '13 at 17:14
  • @editor: when I said global, I was referring to the fact that the starting time is not particularly linked to the clicked object, but stays outside. For example, if your selector involved many elements (like, say, `'div'`), their respective clicks would interfere _via_ the value of `start`. – Mathieu Rodic Jan 29 '13 at 21:01
  • 1
    Tip: this solution can also be useful if you have a draggable element that should also present an optional menu/div. If user clicks quickly (say, below 500 ms), you should show a menu. If mouseup occurs after 500 ms, do not show the menu (user is still clicking and probably wants to drag). – noderman Apr 10 '14 at 17:55
  • The `e.preventDefault()` would need to be in the `.on('click')` event handler. – Redzarf Mar 02 '17 at 18:30
  • This solution is not really correct. In Chrome, if you long press the backwards/forwards navigation buttons in the browser, you get a popup of your browser history links. You do not perform a mouseup to get that list. The long press should only work with a mousedown event. – Johann Jun 20 '17 at 18:58
4

In the two years since this question was asked an awesome plugin called jQuery Finger was invented:

http://ngryman.sh/jquery.finger/

$('div').on('press', function(e) {
    console.log(this, e);
});
Thomas Hunter II
  • 5,081
  • 7
  • 35
  • 54
3

I know this question is pretty old now, but I was looking for something like this and found that Buley's answer was close to what I needed. I figured I'd post what I've done with it to have it function without the mouse up, sort of like an Android longtouch.

// Set the duration of the long press and declare a couple variables
var longpress = 1000;
var start;
var divMouseDown;                       

// Check for mousedown on the element of choice
$("#element").on('mousedown', function(e){
  // Get the time it was clicked
  start = new Date().getTime();

  // See if mouse is still being held down after the longpress duration
  divMouseDown = setTimeout(function(){
    // What we want to happen when mouse is clicked and held for 1 second
  }, longpress);

  // If the mouse leaves the element or is released before the long touch event, 
  // reset variables and stop the function from triggering          
  $("#element").on('mouseup mouseleave', function(){
    if (divMouseDown) {
      clearTimeout(divMouseDown);
    }
    start = 0;
    e.stopPropagation();
  } );

} );
Tim Howey
  • 145
  • 8
3

Short-click & Long-click events - short press prevented in long press

//from e-OS menu script
var longpress = 800;
var start;
var timer;

//short press - show e-OS system menu
//long press - show e-OS settings
$( "#e-OS-menu" ).on( 'mousedown', function( e ) {
    start = new Date().getTime();
    timer = setTimeout(function(){ console.log('long press!'); }, longpress)
}).on( 'mouseleave', function( e ) {
    start = 0;
    clearTimeout(timer);
}).on( 'mouseup', function( e ) {
    if ( new Date().getTime() < ( start + longpress )  ) {
       clearTimeout(timer);
       console.log('short press!');   
    }
});
CoPLaS
  • 1,727
  • 12
  • 21
3

So this is obviously a long way in the future, but for people who want to do this still, a super simple and pretty elegant way to do this is by combining the clearTimeout function with mouseup / mouseout events:

$('#button').mousedown(function(){
   var timer = setTimeout(
    () => {alert('long press occurred');}, 600
   );
}).mouseup(function(){
    clearTimeout(timer);
}).mouseout(function(){
    clearTimeout(timer);
});
#button {
  width: 50px;
  height: 50px;
  background-color: blue;
  color: white;
  display: flex;
  flex-direction: column;
  text-align: center;
  justify-content: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="button">press here</div>
Michael W
  • 59
  • 3
2

You can use the following code (tested in JSFiddle):

$('#foo').mousedown(function(){
   $(this).data('lastPressed', new Date().getTime());
}).mouseup(function(){
    var lastPressed = $(this).data('lastPressed');
    if (lastPressed){
        var duration = new Date().getTime() - lastPressed;
        $(this).data('lastPressed', false);
        if (duration > 2000) {
            alert('Your click lasted more than 2 seconds.');
        } else {
            alert('Your click lasted less than 2 seconds.');
        }
    }
}).mouseout(function(){
    $(this).data('lastPressed', false);
});
Mathieu Rodic
  • 6,637
  • 2
  • 43
  • 49
2

Upgrading and merging Editor and Kevin B replies you can have a fully functional, multi divs, hold-catcher with:

    // Global delta msec timeout
    var delta = 1500;

    $("#foo").on('mousedown', function(event) {

        var thisElement = $(event.currentTarget);
        var deltaTimer = setTimeout(function(){

            console.log('long press!');
            thisElement.removeData('startTimestamp');
        }, delta);

        thisElement.data('startTimestamp', new Date().getTime());
        thisElement.data('timer', deltaTimer);
    }).on('mouseleave', function(event) {

        var thisElement = $(event.currentTarget);
        clearTimeout(thisElement.data('timer'));

        thisElement.removeData('startTimestamp');
        thisElement.removeData('timer');
    }).on('mouseup', function(event) {

        var thisElement = $(event.currentTarget);
        var startTimestamp = thisElement.data('startTimestamp');
        clearTimeout(thisElement.data('timer'));

        if (startTimestamp !== undefined && !isNaN(parseInt(startTimestamp))) {

            if (new Date().getTime() >= (startTimestamp + delta))
               console.log('long press!');
            else
               console.log('short press!');
        }

        thisElement.removeData('startTimestamp');
        thisElement.removeData('timer');
    });
2

This solution executes the action after the time you set. It also cancels the action if you leave the pressed element with the mouse.

var longpress={
        pressed:false,
        longpressed:false,
        presstime:1000
    };

$('#element').on( 'mousedown' , function( event ) {
        longpress.longpressed=false;
        longpress.pressed=true;
        longpress.timeout=setTimeout(function() {
            longpress.longpressed=true;
            //Long press action here!
        },longpress.presstime);
    }).on( 'mouseup' , function( event ) {
        clearTimeout(longpress.timeout);
        if (!longpress.longpressed && longpress.pressed) {
            longpress.pressed=false;
            //Short press action here!
        }
    }).on('mouseleave', function( event ) {
        clearTimeout(longpress.timeout);
        longpress.pressed=false;
    });
PaRoxUs
  • 119
  • 1
  • 11
1

You can get the timestamp when you detect the click on the div thanks to mousedown. Similarly you can get the timestamp when you detect the click release thanks to mouseup.

You then need to compare these two timestamps, if they are greater than 2 seconds (or 2000milliseconds) then you execute your function.

AnthonyLeGovic
  • 2,335
  • 1
  • 13
  • 22
1

Simple. No need for long uneccesary coding.

(function(){
    // how many milliseconds is a long press?
    var offset = 500;

    $(".button").on('mousedown', function(e){
        // holds the start time
        $(this).data('start',new Date().getTime());
        $(this).addClass("selected");
    }).on('mouseup', function(e){
        if (new Date().getTime() >= ($(this).data('start') + offset)){
            //alert('ur click lasted for over 2 secs');
            $(this).addClass("selected");
        }else{
            $(this).removeClass("selected");
        }
    }).on('mouseleave', function(e){
        start = 0;
        //you can add destroy lingering functions on mouse leave
    });

}());

http://jsfiddle.net/donddoug/8D4nJ/

  • When I tried this on my iOS device the default contextMenu popped up and I saw no trace of this working unfortunately... – patrick Aug 06 '18 at 19:51
1

We can calculate the time difference when the mouse clicks and leave. We can get the timestamp when you click and release a button or div using mousedown and mouseup

Here's an example to detect the simple click and 2 seconds long press. Here I have done with a button press. Similarly, you can use div

$(document).ready(function () {

    var pressTime; // store the press time

    $("#pressHere").on('mouseup', function () {

        var holdTime = 2000; //  2 seconds for long press

        if (new Date().getTime() >= (pressTime + holdTime))
            $("#status").text("It's a Long Press...");
        else
            $("#status").text("It's a Short Press...");
      
    }).on('mousedown', function () { // When Button Release
        
    pressTime = new Date().getTime();
    
    }).on('mouseleave', function () {   // When Button Leave
        
    pressTime = 0;
    
    });

});
.input-bar-item {
    display: table-cell;
}
.button-item {
margin: 20px;
    width: 30%;
}
.width100 {
  width: 60%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


 <div class="input-bar-item button-item">
      <button class="btn btn-info" id="pressHere">Press Me</button>
</div>
<div class="input-bar-item width100" id="status"></div>
doraemon
  • 325
  • 1
  • 4
  • 16
Nishal K.R
  • 1,090
  • 11
  • 21
0

My solution

  • supports touch and click
  • makes sure only click or longClick is fired and only once
  • is canceled when mouse/finger is moved away from element
  • suppresses copy/paste being triggered on touch devices
  • requires jQuery
  • tested with jquery 3.6.0

Usage:

    $("#button").longClick(
       function() { //longclick callback
           console.log("long clicked");
       }, 
       function() { //click callback (optional)
           console.log("clicked");
       },
       1000 //Time in ms. Optional
    });

JSFillde: https://jsfiddle.net/01em4yvc/

Code:

    
    (function() {
       /**
        * Register a function to handle long click via mouse or touch
        *
        * @author Torge Kummerow
        */
        $.fn.longClick = function (longClickCallback, clickCallback = null, timeout = 1000) {
            if (longClickCallback == null && clickCallback == null)
                throw new Error("Neither longClickCallback nor clickCallback defined");
            
            let _t = this; //Nailing this to _t for all following function contexts
            
            //Struct to keep track of the state.
            let state = {
                started : false,
                triggered : false,
                timer : null,
                
                clear : function () {
                    state.started = false;
                    state.triggered = false;
                    if (state.timer != null)
                        clearTimeout(state.timer);
                    state.timer = null;
                }
            }
            
            //Disable native longpress touch handling on touch devices (like copy/paste)
            $(_t).css({
                '-webkit-touch-callout' : 'none',
                '-webkit-user-select'   : 'none',
                '-khtml-user-select'    : 'none',
                '-moz-user-select'      : 'none',
                '-ms-user-select'       : 'none',
                'user-select'           : 'none'
            });
        
            //Handling events
            $(_t).on('mousedown mouseup mouseout touchstart touchend touchcancel touchmove', function(event) {
                switch (event.type) {
                    case 'touchstart' :
                    case 'mousedown' :
                        if (state.started)
                            return; //Click handling alread in progress. A touch will trigger both touchstart and mousedown (but mousedown only after touchend)
                            
                        state.clear(); //To be safe
                        state.started = true;
                        
                        //starting a timer when to handle the long press
                        state.timer = setTimeout(function() {
                            //User pressed for long enough to handle the press
                            if (longClickCallback != null && state.started && !state.triggered) {
                                state.triggered = true;
                                longClickCallback(event);
                            }
                        }, timeout);
                        break;
                        
                    case 'touchend' :
                    case 'mouseup' :
                        if (clickCallback != null && state.started && !state.triggered) {
                            //No long press or click handled yet, So fire normal click event if callback was provided
                            state.triggered = true;
                            clickCallback(event);
                        }
                        
                        /*  Delay clearing state because the event order is
                         *  touchstart ... touchend mousedown mouseup
                         *  if not done this way, mousedown will trigger a second click
                         *  This also means the user can only click once every 100 ms which should be fine normally
                         */
                        setTimeout(function() {
                            state.clear();
                        }, 100);
                        
                        break;
                        
                    case 'mouseout' :
                    case 'touchcancle' :
                        // Cancel progress as mouse was moved outside of the element or finger outside of the canvas
                        state.clear();
                        break;
                        
                    case 'touchmove' :
                        // There is no touchout event, so we check ourself if the user is still above the element after
                        // moving. Note that with scrollable content, this will always return false, even if the finger
                        // actually is outside, as the scroll area is ment to move with the finger.
                        // This is especially happening for "rubberband" effects at the edge of scrollable content
                        let x = event.originalEvent.touches[0].pageX;
                        let y = event.originalEvent.touches[0].pageY;
                        let elBelowMouse = document.elementFromPoint(x,y);
                        if ($(_t)[0] != elBelowMouse) {
                            state.clear();
                        }
                        break;
                }
            });
            
            
            return this;
        };
        
    })();
Torge
  • 2,174
  • 1
  • 23
  • 33