AngularJS: reset $timeout for each page switch - javascript

I'm working on my first AngularJS project and I'm working on a timeout that redirects the user to the startpage after a few minutes if they haven't clicked on anything. timeout is called on each page load to restart the timeout.
But the my problem is that restart() is called multiple times. One time for each page/view load. I use ngRoute.
For example if has clicked on three pages, timeout() has now been called three times and when the $timeout reaches the time, restart() is called three times.
myapp.controller(..., [...], function(...) {
function restart() {
$location.path("/slide/1");
}
function timeout() {
var timeoutHandle = $timeout(function() {
$timeout.cancel(timeoutHandle);
restart();
}, timeoutTime);
}
timeout();
}

Try to use this code:
var redirectTimeout;
var redirect = function() {
$location.path("/slide/1");
}
$timeout.cancel(redirectTimeout);
redirectTimeout = $timeout(function() {
var timeoutTime = 5000 // five seconds
redirectTimeout = $timeout(redirect, timeoutTime);
});
Here is the JSFiddle

Wouldn't it be better to put this kind of functionality inside a factory?

Related

Reliably clear intervals when switching page on a dynamic app

I load all content inside a div in the index. Some of these pages require starting intervals, and when switching page those intervals keep going, so I created a destroyjs() function which gets overridden by pages that need it, and is also called every time you switch pages.
The goServiceXXX functions are called onclick in the website's navbar.
var destroyjs = function(){};
function loading(elem)
{
if (typeof destroyjs == 'function')
destroyjs();
document.getElementById("mbody").innerHTML = '<div class="container4"><img src="dist/img/loading.gif" alt="Loading..."></div>';
}
function goServiceManager()
{
var element = "#mbody";
var link = "loadservicemanager.php";
loading(element);
$(element).load(link, function(){
reloadServerStatus();
statusInterval = setInterval(function()
{
reloadServerStatus();
}, 2000);
destroyjs = function(){
clearInterval(statusInterval);
clearInterval(modalInterval);
alert("destroyed manager, interval #"+statusInterval);
}
});
}
function goServiceMonitor()
{
var element = "#mbody";
var link = "loadservicemonitor.php";
loading(element);
$(element).load(link, function(){
reloadServerStatus();
statusInterval = setInterval(function()
{
reloadServerStatus();
}, 2000);
destroyjs = function(){
clearInterval(statusInterval);
alert("destroyed monitor, interval #"+statusInterval);
}
});
}
This works fine when used normally however if I spam click between the two pages, intervals start adding up and the 2 second query is now being called 10 times every two seconds. I added the alerts to debug but they slow the interface down enough for everything to work properly.
Is there a hole in my logic somewhere? I already thought of disabling all navbar buttons when one is clicked and enabling them at the end of .load; but I'd like to know why my current implementation is not working and if it can be fixed more easily.
Edit:: So I tried to make a fiddle with the problem and in the process realized that the problem happens when destroyjs() is called before .load() finishes. Moving the interval right before .load() fixes the problem but can create a scenario where if the content never loads (or doesn't load in two seconds) there are missing elements which the function inside the interval tries to fill. Disabling the navbar temporarily and wait for .load to finish is the easy way out after all but I'd still like more opinions on this or maybe ideas for a better implementation.
destroyjs isn't defined until the load() completes. If you switch tabs before the previous tab has loaded, you won't be able to call the correct destroyjs.
Therefore, you will want to cancel any outstanding load requests when switching tabs. To do this, you can use jQuery's ajax method. Just store a reference to the resulting XHR object and call abort() when loading a new tab. Aborting an outstanding ajax request will prevent it's success callback from firing.
Here's an example (DEMO FIDDLE). Notice that I've also changed the way that intervals are cleared:
//ajax request used when loading tabs
var tabRequest = null;
//Any intervals that will need to be cleared when switching tabs
var runningIntervals = [];
function loading(elem)
{
if (tabRequest) {
//Aborts the outstanding request so the success callback won't be fired.
tabRequest.abort();
}
runningIntervals.forEach(clearInterval);
document.getElementById("mbody").innerHTML = '<div>Loading...</div>';
}
function goServiceManager()
{
var element = "#mbody";
var link = "loadservicemanager.php";
loading(element);
tabRequest = $.ajax({
url: link,
success: function(data) {
$(element).html(data);
reloadServerStatus();
statusInterval = setInterval(reloadServerStatus, 2000);
modalInterval = setInterval(modalFunction, 2000);
runningIntervals = [statusInterval, modalInterval];
}
});
}
function goServiceMonitor()
{
var element = "#mbody";
var link = "loadservicemonitor.php";
loading(element);
tabRequest = $.ajax({
url: link,
success: function(data) {
$(element).html(data);
reloadServerStatus();
statusInterval = setInterval(reloadServerStatus, 2000);
runningIntervals = [statusInterval];
}
});
}

Redirect with inactivity

My objective is to keep a user in a view as long as he/she keeps clicking a button within a certain lapse.
I'm using Rails and was exploring a solution via an embedded JS in the pertinent view.
So far I'm able to set a time after which the user will be redirected to root path with the following script:
var delayedRedirect = function (){
window.location = "/";
}
var delay = 10000;
$(document).ready(function() {
setTimeout('delayedRedirect()', delay);
});
I've been trying to write a function that resets the value of 'delay'or that calls the setTimeoutFunction again.
$('#btn-persist').click(function() {
delay = 3000;
// or calling again setTimeout('delayedRedirect()', delay);
});
But I noticed that changing the variable won't affect the setTimeout function that has already been called.
I've also tried to use the clearTimeout function as below without success
var delayedRedirect = function (){
window.location = "/persists";
}
var delay = 3000;
var triggerRedirect = function() { setTimeout('delayedRedirect()', delay);
}
var stopRedirect = function (){
clearTimeout(triggerRedirect);
}
$(document).ready(function() {
triggerRedirect();
$('#btn-persist').click(function() {
stopRedirect();
});
});
I wonder why this may not be working and if there's any other way to stop the execution of the setTimeout function that has already been called so I can call it again to effectively reset the time to the original value of 'delay'.
At the same time, I don't want to stop any other JS functions that are running in parallel.
Do you see a better solution to achieve this?
The main problem why clearTimeout is not working. because you are clearing a anonymous function instead of a setTimeout variable
change this
var triggerRedirect = function() { setTimeout('delayedRedirect()', delay);
}
to this
var triggerRedirect = setTimeout('delayedRedirect()', delay);
Edit:
also change this (if you want to restart the inactive redirect trigger)
$('#btn-persist').click(function() {
stopRedirect();
});
to this
$('#btn-persist').click(function() {
stopRedirect();
triggerRedirect();
});

$timeout continues to run after page click to other path

I am using yo:angular-fullstack generator to build my website. When a user registers to the site, it will send an activation email with a link. When a user clicks the link, it will show activation successful and a timeout to go to the home page. However, when the timeout has not finished and the user clicks any other link in the page, it jumps to other page with continuing running the timeout. Severally seconds later, the user will be still moved to the home page.
$scope.countdown = 10;
$scope.onTimeout = function() {
$scope.countdown--;
timer = $timeout($scope.onTimeout, 1000);
if ($scope.countdown === 0) {
$timeout.cancel(timer);
$location.path('/');
}
};
var timer = $timeout($scope.onTimeout, 1000);
I don't know how to cancel the timer when the user clicks other links in this page.
You need to listen to AngularJS changing the route using the $locationChangeStart event:
$scope.$on('$locationChangeStart', function () {
$timeout.cancel(timer);
});
That way, when the route changes, the timer is cancelled and the user is not redirected.
module.controller("TestController", function($scope, $timeout) {
var onTimeout = function() {
// something
};
var timer = $timeout(onTimeout, 1000);
$scope.$on("$destroy", function() {
if (timer) {
$timeout.cancel(timer);
}
});
});
you can call it simply when scope is destroyed.

How to reload a page automatically after a given period of time if user is not active in angularjs

I want to reload a page in every 5 min if a user is not active on that page.(I don't want reload a page while user is active).
I have a code for reloading a page while clicking on the button.
<button ng-click="refreshDeliveries()">
<span>Refresh Deliveries</span>
</button>
$scope.refreshDeliveries = function () {
$window.location.reload();
};
But I just want if user is not active from past 5 min, page will automatically reloaded in Angularjs.
Thank you
You can use $interval method from angularJS
function reloadPage() {
var d = new Date();
var curTime = d.getTime(); //n in ms
$window.location.reload();
}
to set in 5 minutes
setIntvl = $interval(reloadPage, 300000);
cancel a interval
$interval.cancel(setIntvl);
This code works for me
and for auto idle refresh check
Auto logout with Angularjs based on idle user
This code sample might be helpful for you. It uses Angular 1.3 and https://github.com/HackedByChinese/ng-idle library:
(function() {
angular.module('myApp', ['ngIdle'])
.controller('ctrl', homeController)
.config(function(IdleProvider, KeepaliveProvider) {
// configure Idle settings
IdleProvider.idle(5); // in seconds
IdleProvider.timeout(5); // in seconds
KeepaliveProvider.interval(2); // in seconds
})
.run(function(Idle) {
// start watching when the app runs. also starts the Keepalive service by default.
Idle.watch();
});
function homeController($scope, Idle) {
$scope.message = 'Check browser console to get idle info';
$scope.events = [];
$scope.$on('IdleStart', function() {
console.log('Idle Start');
// the user appears to have gone idle
});
$scope.$on('IdleWarn', function(e, countdown) {
console.log(e, countdown);
// follows after the IdleStart event, but includes a countdown until the user is considered timed out
// the countdown arg is the number of seconds remaining until then.
// you can change the title or display a warning dialog from here.
// you can let them resume their session by calling Idle.watch()
});
$scope.$on('IdleTimeout', function() {
console.log('Idle Timeout');
// the user has timed out (meaning idleDuration + timeout has passed without any activity)
// this is where you'd log them
// ------You can reload the page here------
});
$scope.$on('IdleEnd', function() {
console.log('Idle End');
// the user has come back from AFK and is doing stuff. if you are warning them, you can use this to hide the dialog
});
$scope.$on('Keepalive', function() {
console.log('Keep me Alive');
// do something to keep the user's session alive
});
}
}());

Image refreshing with setInterval()

I have 4 divĀ“s each contains an image item and a select list of 4 div-id. I want to refresh the images simultaneously by changing the source of each image every 2 seconds.
I'm using setInterval() for each image and the problem is when I must stop all the timers at the same time.
Should I make a timer variable per div/img?
$(.div-id option:selected).each(function(){
var timer = setInterval(function(){
$(.div-id img).attr("src", "new-source-path");
},2000);
});
How can I stop all the active timers at once without stopping every timer Id?
Is there any solution with setTimeout() or any plugin to do that?
I'd opt for a single timer that loops through all images. Then when the timer isn't needed anymore I can just discard the single timer.
var timer = setInterval(swapImages, 2000);
function swapImages() {
$(.div-id option:selected).each(function(){
$(.div-id img).attr("src", "new-source-path");
});
}
// some time later
clearInterval(timer);
PS. I assume that your code is some pseudo code so I copied your namings
The end solution
function swapImages() {
$(".div-id-list option:selected").each(function () {
var url = "new-source-path";
$("#div-id img").attr("src", url);
});
}
function stopTimer() {
clearInterval(timer);
}
$(".div-id-list").on("change", function () {
stopTimer();
timer = setInterval(swapImages, 2000);
});
Thanks to donnywals !

Categories

Resources