ng-idle issue if multiple tabs/windows are opened in browser
Asked Answered
C

2

8

I have a requirement where I have to logout user if it is idle for some time. I am using ng-idle 0.3.2.

I am getting issue if there are more than one tabs/windows opened in browser. If I am working on a tab and the tabs which are not active getting logged-out while the active tab I am working on is still logged-in because that is active.

How to prevent logout from inactive tabs while I am working on another similar tab?

Calefaction answered 1/5, 2014 at 19:5 Comment(4)
You need to be communicating between your tabs - look @ #12107924Wordbook
I don't have any experience with ng-idle but after reading over the docs, it looks like it was designed for single-window use. I wonder though if you could register each window/tab in localStorage then when $idleTimeout is fired, check with that LS value to make sure other windows aren't still active. Of course, there would be more to it than that but hopefully that's a lead...Meitner
@MikePugh that communication will not work as user can open pages by typing in urls.Calefaction
@marck, Yes, that will work but it will be my last option :)Calefaction
M
8

Summary

Use localStorage to store a timestamp for the last known activity event in any tab running your app. Poll that value every few seconds in every instance of your app that is running. If it has been updated, reset the ng-idle timer to avoid premature logout (or whatever action you have set to occur when the $idleTimeout event is broadcast).

How To

Create a directive to embody the behavior described above:

.directive('idle', function($idle, $timeout, $interval){
  return {
    restrict: 'A',
    link: function(scope, elem, attrs) {
      var timeout;
      var timestamp = localStorage.lastEventTime;

      // Watch for the events set in ng-idle's options
      // If any of them fire (considering 500ms debounce), update localStorage.lastEventTime with a current timestamp
      elem.on($idle._options().events, function(){
        if (timeout) { $timeout.cancel(timeout); }
        timeout = $timeout(function(){
          localStorage.setItem('lastEventTime', new Date().getTime());
        }, 500);
      });

      // Every 5s, poll localStorage.lastEventTime to see if its value is greater than the timestamp set for the last known event
      // If it is, reset the ng-idle timer and update the last known event timestamp to the value found in localStorage
      $interval(function() {
        if (localStorage.lastEventTime > timestamp) {
          $idle.watch();
          timestamp = localStorage.lastEventTime;
        } 
      }, 5000);
    }
  }
})

Add the directive attribute to the body tag to ensure that all mouse and keyboard events within the page are detected:

<body ng-app="myApp" idle>

Demo

Open up and run this Plunk in multiple tabs along with a console for each. Move your mouse cursor over the body content and watch the events logged to both consoles.

Meitner answered 2/5, 2014 at 4:44 Comment(0)
S
2

I haven't worked with ngIdle yet but typically you need to communicate with server in these situations. i.e. In $keepalive event, send a request to server to store the last activity time in session. In the $idleWarn, send a request to server to get the latest activity time stamp, if user is active in other tabs then you would get a recent timestamp, hence you can stop the timeout process and send a keepalive.

Sedgewake answered 1/5, 2014 at 20:24 Comment(1)
As I mentioned in the comments, localStorage could be used to store such a timestamp in a way that all windows could get to it without a server trip. And would they really want to reset the timer every time $keepalive is broadcasted? ..with multiple tabs/windows open, it seems that it might cause the idle timers to never run down. Not saying that problem couldn't be handled, but this all seems a bit tricky with this lib.Meitner

© 2022 - 2024 — McMap. All rights reserved.