In the below given code, we are calling startTimer function , where we use $interval to trigger the request to backend until we get the data.status == "complete" ;and once status is completed ,we set the flag = true and flag will lead to trigger the watch and it calls the $scope.stop function to cancel the timer using $interval.cancel.
But here issue arises i.e. , $interval.cancel doesn't know which timer to stop first.
When there are multiple request to call the timer based on id, the completed timer based on that id should get cancelled.
So my question is How to cancel the timer based on the id.
angular.module('timerApp', ['timerApp.controllers']);
angular.module('timerApp.controllers', []).controller('timerController', ['$scope', '$interval',
function($scope, $interval) {
var timer;
var time = 10;
$scope.countdown = time;
$scope.startTimer = function(id) {
timer = $interval(function(id) {
$scope.countdown--;
//res is response from my backend
someRestService(id).then(res);
var data = res;
if (data.status = "complete") {
$scope.timerFlag = true;
}
}, 15000);
};
}
$scope.stopTimer = function() {
$interval.cancel(timer);
};
$scope.$watch() {
if ($scope.timerFlag == true) {
$scope.stopTimer();
}
}
]);
scenario :
RestapiHit/627
RestapiHit/628
RestapiHit/629
it will call the 627 request and finish the process and then when about to cancel using $interval.cancel it goes for latest one and cancel the 629 but not 627
Take a look at:
angular.module('timerApp', ['timerApp.controllers']);
angular.module('timerApp.controllers', []).controller('timerController', ['$scope', '$interval',
function($scope, $interval) {
var timer= {} ;
var time = 10;
$scope.countdown = time;
$scope.startTimer = function(id) {
timer[id] = $interval(function(id) {
$scope.countdown--;
//res is response from my backend
someRestService(id).then(res);
var data = res;
if (data.status = "complete") {
$scope.stopTimer(id);
}
}, 15000);
};
}
$scope.stopTimer = function(id) {
$interval.cancel(timer[id]);
delete timer[id];
};
]);
Right now, you just have one timer value assigned as it is declared at controller level. But since, you might have multiple calls for $interval so i think this approach should work better.
Related
Is there a way to add a timeout to an AngularJS $watch function?
For example, let's say I have the below AngularJS code that's watching a value, myName. When the value changes, the listener function runs. But if the value does not change within a certain period of time, I want it to do something else.
Specifically, in the code below, I would want $scope.nothingEnteredFlag to change from false to true. My html template be set up to reflect the state of that flag (e.g., using ng-show).
var app = angular.module("helloApp", []);
app.controller("helloCtrl", function($scope) {
$scope.nothingEnteredFlag=false;
$scope.$watch("myName", function (newValue, oldValue) {
if ($scope.myName.length < 5) {
$scope.message = "Short name!";
} else {
$scope.message = "Long name!";
}
});
});
See fiddle.
I've tried surrounding the $watch with $timeout, but can't seem to get that to work.
You can use angular timeout to achieve your desire result.
var timer;
var timerFunction = function() {
timer = $timeout(function() {
$scope.nothingEnteredFlag = true;
}, 5000);
};
This is will create the timer function
Your controller should like this
var app = angular.module("helloApp", []);
app.controller("helloCtrl", function($scope, $timeout) {
$scope.nothingEnteredFlag = false;
$scope.myName = "";
$scope.$watch("myName", function(newValue, oldValue) {
if ($scope.myName.length < 5) {
$scope.message = "Short name!";
} else {
$scope.message = "Long name!";
}
$scope.nothingEnteredFlag = false;
$timeout.cancel(timer);
timerFunction();
});
var timer;
var timerFunction = function() {
timer = $timeout(function() {
$scope.nothingEnteredFlag = true;
}, 5000);
};
timerFunction();
});
As you can see we have enabled timeout of the 5 seconds once user enters any text we cancel the timer and enable it again, this way we can prompt the user to enter if he hasn't wrote anything in five seconds.
Demo
I have used $timeout to call an angular JS service in every 5 seconds. But it leads to a page or cursor reload in my application. Can anyone assist me to stop the page reload?
var app = angular.module('myApp', ['ngAnimate']);
app.controller('MainCtrl', function($scope, $http, $timeout) {
var loadTime = 1000, //Load the data every second
errorCount = 0, //Counter for the server errors
loadPromise; //Pointer to the promise created by the Angular $timout service
var getData = function() {
//console.log('http://httpbin.org/delay/1?now=' + Date.now());
$http.get('http://httpbin.org/delay/1?now=' + Date.now())
.then(function(res) {
$scope.data = res.data.args;
errorCount = 0;
nextLoad();
})
.catch(function(res) {
$scope.data = 'Server error';
nextLoad(++errorCount * 2 * loadTime);
});
};
var cancelNextLoad = function() {
$timeout.cancel(loadPromise);
};
var nextLoad = function(mill) {
mill = mill || loadTime;
//Always make sure the last timeout is cleared before starting a new one
cancelNextLoad();
loadPromise = $timeout(getData, mill);
};
//Start polling the data from the server
getData();
//Always clear the timeout when the view is destroyed, otherwise it will keep polling and leak memory
$scope.$on('$destroy', function() {
cancelNextLoad();
});
$scope.data = 'Loading...';
});
Check to make sure loadPromise exists before cancelling it:
var cancelNextLoad = function() {
̶$̶t̶i̶m̶e̶o̶u̶t̶.̶c̶a̶n̶c̶e̶l̶(̶l̶o̶a̶d̶P̶r̶o̶m̶i̶s̶e̶)̶;̶
loadPromise && $timeout.cancel(loadPromise);
};
I am trying show a timeout error message after particular interval of idle time(say 10 mins)
I followed the below link and it is working as expected.
https://long2know.com/2015/04/user-session-timeout/
var idleService = function ($rootScope, $timeout, $log) {
var idleTimer = null,
startTimer = function () {
$log.log('Starting timer');
idleTimer = $timeout(timerExpiring, 10000);
},
stopTimer = function () {
if (idleTimer) {
$timeout.cancel(idleTimer);
}
},
resetTimer = function () {
stopTimer();
startTimer();
},
timerExpiring = function () {
stopTimer();
$rootScope.$broadcast('sessionExpiring');
$log.log('Timer expiring ..');
};
startTimer();
return {
startTimer: startTimer,
stopTimer: stopTimer,
resetTimer: resetTimer
};
};
Is it possible to achieve it without the $broadcast and $on. Any guidance on how to make the controller variable know when the timeout is expired, currently it is achieved via $broadcast from service and $on on controller and then the variable will be modified in $on function.
You could use RxJS to create an observable. Your controller would subscribe to it through your service and when the timeout is expired, a value is emitted on your observable (could be a void value). This way, every controller that has a subscription on that observable would receive the signal that the timeout is expired.
I did a plunker to illustrate this: https://plnkr.co/edit/JSgKWLwQLAhqgRGPn9ys
First, you start by creating a method that returns an observable. I'm using a Subject as you don't need to send an initial value or a value that has already been emitted:
var getExpiredSignal = function() {
return subject.asObservable();
}
Now, when you timeout is expired, you need to send a signal through the observable by doing:
subject.next();
As your controller did subscribe to this observable via the line:
timeout.getExpiredSignal().subscribe(() => console.log('Expired!'));
The callback function logging "Expired" is triggered.
I made it work with the below approach
var idleService = function ($rootScope, $timeout, $log) {
var idleTimer = null,
startTimer = function () {
$log.log('Starting timer');
idleTimer = $timeout(timerExpiring, 10000);
},
stopTimer = function () {
if (idleTimer) {
$timeout.cancel(idleTimer);
}
},
resetTimer = function () {
stopTimer();
startTimer();
},
timerExpiring = function () {
stopTimer();
$rootScope.sessionFlag = true;
$log.log('Timer expiring ..');
};
startTimer();
return {
startTimer: startTimer,
stopTimer: stopTimer,
resetTimer: resetTimer
};
};
Now I am not using $broadcast and $on but I am changing the $rootscope.sessionFlag which I am referencing in my html
I am Creating a web app
on my button click there is an insert query if after (15 seconds) it is unable to insert, it should show the message (in alert) the internet connection is very slow Please Wait For A While
How To Use timer in angularjs?
Instead if $timeout, IMO $interval will be of more help.
Below is the sample snippet for doing the same
function FetchCtrl($scope, $http, $interval) {
$scope.method = 'GET';
$scope.url = 'http-hello.html';
$scope.count = 0;
var stop;
var stopInterval = function(){
$interval.cancel(stop);
stop = undefined;
$scope.count=0;
}
$scope.fetch = function() {
stop = $interval(function(){
$scope.count++;
if($scope.count === 15){
//showAlert here
stopInterval();
}
},1000);
$http({method: $scope.method, url: $scope.url})
.success(function(data, status) {
stopInterval();
$scope.status = status;
$scope.data = data;
})
.error(function(data, status) {
stopInterval();
$scope.status = status;
$scope.data = "Request failed";
});
};
$scope.$on('$destroy', function() {
// Make sure that the interval is destroyed too
stopInterval();
});
}
Here the interval is started as soon as http request is made, it updates the counter every second for 15 seconds. Then once 15 is reached, alert is shown and the interval is stopped.
If the request is completed, then also the interval is stopped.
PS: While using $interval, one thing should be kept in mind : Cancel the interval when scope is destroyed otherwise it will continue to execute callback even when we have moved out of that controller scope.
I'm trying to make a little notifier, that informs about typical situations: need authorization, changes saved etc. Notices are shown for 3 seconds and disappear, if user didn't click on it (if notice clicked, it disappears immediatly).
Documentation is not very informative.
How should i use $timeout, to call close(); after 3 seconds?
And how can i put a variable (nId) into function? I tried with closure (*function(){return function(){}}*) in default setTimeOut(), but unsuccessfully.
myApp.controller('noticesCtrl',
function noticesCtrl($scope, $rootScope, noticesData){
$rootScope.notices = [];
$scope.closeNotice = function(nId){
noticesData.close(nId);
};
});
myApp.factory('noticesData', function($rootScope, $timeout){
return{
add: function(type, text){
var nId = $rootScope.notices.length + 1;
$rootScope.notices.push({id: nId, type:type, text:text+nId});
// call close function with 3sec. delay; how?
},
close: function(nId){
angular.forEach($rootScope.notices, function(notice, key){
if(notice.id == nId){
$rootScope.notices.splice(key,1);
}
});
}
}
});
myApp.factory('noticesData', function($rootScope, $timeout){
var obj = {};
obj.add = function(type, text){
var nId = $rootScope.notices.length + 1;
$rootScope.notices.push({id: nId, type:type, text:text+nId});
$timeout(function(){
obj.close(nId);
},3000);
}
obj.close = function(nId){
angular.forEach($rootScope.notices, function(notice, key){
if(notice.id == nId){
$rootScope.notices.splice(key,1);
}
});
}
return obj;
});
Heres how to do it
$timeout(function () {
// do something
}, 50);