Adding a delay in AngularJS forEach - angularjs

I'm trying to put a delay in a forEach loop in AngularJS. With $timeout, they're firing once at the same time. With $interval, they're caught in an infinite loop, again at the same time.
I need the function delay between iterations of the forEach loop to fire the animations in delayed succession rather than at the same time.
...
vm.questions = [
{correct:false,animateDemo:false},
{correct:true,animateDemo:false},
{correct:true,animateDemo:false}
];
vm.questions.forEach(function(question, idx) {
// need a delay between animationDemo assignments
$timeout(function(){
if (question.correct) {
question.animateDemo = true;
}
},1000);
});
I tried interval too, but that causes an infinite loop.
vm.questions = [{correct:false}. {correct:true}, {correct:true}];
vm.questions.forEach(function(question, idx) {
// causes infinite loop
$interval(function(){
if (question.correct) {
question.animateDemo = true;
}
},1000);
});
I'm sure the solution is probably something simple, but getting it in this syntax is a bit confusing to me personally.

What you can do is have a dynamic timeout for each question animation.
Something like this:
var timeoutTimer = 1000;
vm.questions.forEach(function(question, idx) {
$timeout(function(){
if (question.correct) {
question.animateDemo = true;
}
}, timeoutTimer);
timeoutTimer += 1000;
});
You want to use $timeout and not $interval since you only want each animation to trigger once. $interval will execute every x seconds until you cancel it.
$timeout is a promise so code will continue to execute while it waits for the delay. This is why it appears they are all firing at the same time. They actually are probably a few nanoseconds apart from each other.

Related

cancel process without using delay task

I have the following delay task in the below method:
exportDataToCSV: function () {
var me = this,
grid = this.option.up('grid');
var mask = Ext.widget('processingmessagebox', {
target: grid,
progressMessage: 'exporting',
isProcessing: true,
targetFunctions: {
ConfirmCancelClick: me.stopExportingData
}
});
mask.getViewModel().set({ ShowCancelBox: 'block' });
var grdStore = grid.getStore();
var grdProxy = grdStore.getProxy();
exportData = new Ext.util.DelayedTask(function () {
me.printDataToCSV(grid, mask);
});
exportData.delay(2000);
},
stopExportingData: function () {
exportData.cancel();
}
This is working fine. But, I am trying to cancel the "exportdata" process without using delay task. Any suggestions on this?
You kind of can't. Javascript - and thus ExtJS - is single-threaded. If your code is busy doing something, it can't respond to a cancel button.
In order to make a long-running task cancelable - or even just to allow a progress bar to update - it needs to be broken up into a series of steps. These steps need to then be put on the task queue - something that ExtJS's delayed task does for you.
For something like export data to a CSV, a common approach would be to create a task that exports, say, a dozen records, and then puts another task to read the next dozen.
There are certainly other approaches than using DelayedTask in particular, but they all revolve around the underlying setTimeout or setInterval methods.
Here's an example using a regular ExtJS task, and not DelayedTask:
var readNextDozenRecords = function(indexToReadFrom) { ... }
var writeDataChunk = function(recordsToWrite) { ... }
var taskConfig = {
currentIndex: 0,
interval: 10, // runs every 10ms or so.
run: function() {
var nextDataChunk = readNextDozenRecords(currentIndex);
if (nextDataChunk.length == 0) {
this.stop(); // 'this' scope is the running task.
return;
}
currentIndex += nextDataChunk.length;
writeDatakChunk(nextDataChunk);
}
}
exportData = Ext.TaskManager.newTask(taskConfig);
// The exportData can be manually canceled by calling the `stop` method.

Run function when resize finished (without underscope.js)?

From controller i detect resize event for $window and restart my carousel directive after it .
But the problem is , that carusel restart nearly 5-6 times . I cant find any helpful solution about this .
angular.element($window).bind('resize', function () {
$scope.$apply(function(){
$scope.showCarousel = false;
$timeout(function(){
$scope.calculateGamesCount();
$scope.showCarousel = true;
}, 250);
});
});
How can i detect , if resize event is finished then run functions ?
Unfortunately, there's no such event as "resize done" that we can hook into. Each pixel change is its own independent event. If a third party solution is 100% out of the question, you could implement your own home-grown debounce:
function debounce(f, n){
let allow_run = true;
return function(...args){
if(allow_run){
allow_run = false;
setTimeout(_=> allow_run = true, n);
return f.apply(f, args);
}
}
}
window.onresize = debounce(_=> console.log('resizing!'), 250);
Essentially, we have a gatekeeper, allow_run. If the debounced function is called while the gate is "open", execution is allowed, and the gate is closed until the timeout (n milliseconds) expires. If the debounced function is called with the gate "closed", nothing happens.
demo

angular `$broadcast` issue - how to fix this?

In my app, I am boradcasting a event for certain point, with checking some value. it works fine But the issue is, later on whenever i am trigger the broadcast, still my conditions works, that means my condition is working all times after the trigger happend.
here is my code :
scope.$watch('ctrl.data.deviceCity', function(newcity, oldcity) {
if (!newcity) {
scope.preloadMsg = false;
return;
}
scope.$on('cfpLoadingBar:started', function() {
$timeout(function() {
if (newcity && newcity.originalObject.stateId) { //the condition not works after the first time means alwasy appends the text
console.log('each time');
$('#loading-bar-spinner').find('.spinner-icon span')
.text('Finding install sites...');
}
}, 100);
});
});
you can deregister the watcher by storing its reference in a variable and then calling it:
var myWatch = scope.$watch('ctrl.data.deviceCity', function(){
if( someCondition === true ){
myWatch(); //deregister the watcher by calling its reference
}
});
if you want to switch logic, just set some variable somewhere that dictates the control flow of the method:
var myWatch = scope.$watch('ctrl.data.deviceCity', function(){
scope.calledOnce = false;
if(!scope.calledOnce){
//... run this the first time
scope.calledOnce = true;
}
else {
// run this the second time (and every other time if you do not deregister this watch or change the variable)
// if you don't need this $watch anymore afterwards, just deregister it like so:
myWatch();
}
})

Possibility of changing $interval interval on runtime - Angular

I need to change the interval value based on user inputs as following:
scope.refreshEvery = 1000;
//run on startup every 1 second
scope.interval = $interval(function () {
scope.refresh(scope.page);
}.bind(this), refreshEvery);
//onclick will change the interval to 2 seconds
scope.onclick = function () {
scope.refreshEvery = 2000;
}
I have seen few solutions for JS setTimeout with recursive but that will not work here specially from a performance aspect as its recommended to cancel all the timeout and interval with the scope destroying event.
Is this possible with angular $interval!

How to remove all running $interval in AngularJS?

Hi i want to remove all running $interval in Angular. in my page there are many $interval and on button click i want to remove all interval.How will i do it .
Any help is appreciated.
According to the documentation $interval returns a promise, and the interval can be cancelled using $interval.cancel(promise).
I can't see any methods for cancelling all intervals, but if you keep the returned promises in an array you can iterate over that to cancel them all.
var intervals = []
intervals.push($interval(function() { /*doStuff*/ }, /*timeout*/));
intervals.push($interval(function() { /*doDifferentStuff*/ }, /*timeout*/));
...
angular.forEach(intervals, function(interval) {
$interval.cancel(interval);
});
intervals.length = 0; //clear the array
If your intervals are spread over different controllers, use a service to keep track of them.
A more performant approach :
var intervals = [];
intervals.push($interval(function() { /*doStuff*/ }, /*timeout*/));
intervals.push($interval(function() { /*doDifferentStuff*/ }, /*timeout*/));
//doing some stuff
while(intervals.length){
$interval.cancel(intervals.pop());
}

Resources