Akira Dawson
Akira Dawson

Reputation: 1267

How to use mouse event to do AJAX call only if user is idle for X seconds

Apologies if this is a repost. I have seen many examples. But I can't seem to put together my needs. I have a "today" page which displays all groups. Throughout the day more and more groups will appear. I want to be able to dynamically update these groups if the user has the page open and hasn't moved the mouse for X seconds. I have this chunk of code:

var timeout = null;
    j$(document).on('mousemove', function() {
        if (timeout !== null) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(function() {
            timeout = null;
            //calls another page to check if there's new data to display. if so, wipe existing data and update
            j$.ajax({
                  url: "/include/new_Groups.php",
                  cache: false,
                  success: function(data){
                      j$( ".group_Container_Main" ).append( data ).fadeIn('slow');
                  }
                })
                  .done(function( html ) {
              });
        }, 3000);
    });

What this is doing is if the user hasn't moved the mouse after 3 seconds, do an AJAX call to update the group. This semi works. If you don't move the mouse, it will update. But it won't update again unless the mouse is moved and idle again for 3 seconds which is not good user experience.

I'm trying to find a way to just continually update the page every 3 seconds (for this example) if the user is idle. But if he's moving the mouse, there is to be no updating. Please ask questions if I'm unclear! Thanks in advance.

Upvotes: 2

Views: 1245

Answers (4)

adeneo
adeneo

Reputation: 318212

Should be straigh forward, use an interval and a function call instead

jQuery(function($) {
    var timer;

    $(window).on('mousemove', function() {
        clearInterval(timer);
        timer = setInterval(update, 3000);
    }).trigger('mousemove');

    function update() {
        $.ajax({
            url    : "/include/new_Groups.php",
        }).done(function (html) {
            $(".group_Container_Main").append(html).fadeIn('slow')
        });
    }
});

FIDDLE

EDIT:

To solve the issue of stacking ajax requests if for some reason they take more than three seconds to complete, we can just check the state of the previous ajax call before starting a new one, if the state is pending it's still running.

jQuery(function($) {
    var timer, xhr;

    $(window).on('mousemove', function() {
        clearInterval(timer);
        timer = setInterval(update, 1000);
    }).trigger('mousemove');

    function update() {
        if ( ! (xhr && xhr.state && xhr.state == 'pending' ) ) {
            xhr = $.ajax({
                url    : "/include/new_Groups.php",
            }).done(function (html) {
                $(".group_Container_Main").append(data).fadeIn('slow')
            });
        }
    }
});

Upvotes: 4

APerson
APerson

Reputation: 8422

You should use setInterval() instead of setTimeout() to make a repeating event.

I would call setInterval() outside of your event handler code, and then make your event handler code update a lastTimeMouseMoved (or something) timestamp, which would be checked by the code passed to your setInterval() call.

So, your code might look like this:

const IDLE_TIME = 3000;
var lastTimeMouseMoved = Date.now();

timer = setInterval(function() {
    if(Date.now() - lastTimeMouseMoved >= IDLE_TIME) {
        //calls another page to check if there's new data to display. if so, wipe existing data and update
        j$.ajax({
            url: "/include/new_Groups.php",
            cache: false,
            success: function(data){
                j$( ".group_Container_Main" ).append( data ).fadeIn('slow');
            }
        })
            .done(function( html ) { });
    } // end idle if
}, IDLE_TIME);

j$(document).on('mousemove', function() {
    lastTimeMouseMoved = Date.now();
});

Upvotes: 0

Fenton
Fenton

Reputation: 250932

You can invert your timer idea to this logical connection...

  1. Set a timer for 3 seconds after which you will do the AJAX call

  2. If the mouse is moved, reset the timer for 3 seconds

You now have a three second timer running whether or not the mouse is moved and you reset it on mouse move to get the behaviour you want in respect of only updating on idle.

var timeout = setTimeout(update, 3000);

function update() {
    clearTimeout(timeout);
    //calls another page to check if there's new data to display. if so, wipe existing data and update
    j$.ajax({
          url: "/include/new_Groups.php",
          cache: false,
          success: function(data){
              j$( ".group_Container_Main" ).append( data ).fadeIn('slow');
          }
        }).done(function(html) {

        }).always(function() {
              timeout = setTimeout(update, 3000);
       });
}

j$(document).on('mousemove', function() {
    clearTimeout(timeout);
    timeout = setTimeout(update, 3000);
});

Upvotes: 1

Karl-André Gagnon
Karl-André Gagnon

Reputation: 33870

On the AJAX parameter, use the complete option to trigger a mouse move :

j$(document).on('mousemove', function() {
    if (timeout !== null) {
        clearTimeout(timeout);
    }
    timeout = setTimeout(function() {
        timeout = null;
        //calls another page to check if there's new data to display. if so, wipe existing data and update
        j$.ajax({
              url: "/include/new_Groups.php",
              cache: false,
              success: function(data){
                  j$( ".group_Container_Main" ).append( data ).fadeIn('slow');
              },
              complete: function(data){
                  j$(document).trigger('mousemove');
              }
            })
              .done(function( html ) {
          });
    }, 3000);
});

Upvotes: 1

Related Questions