angularJS stop the $interval call after an IF condition is true - javascript

I am trying to reload my models every 5000 milliseconds for which I am using the AngularJS $interval function to invoke my init () method. I want to stop reloading the models after all the values in a list are "COMPLETED" or no value in a given list is either Processing. Any Clue how to achieve this ?
function DeliveriesController(deliveriesService, $interval){
var vm = this;
vm.defaultWorkspace = 'HOT_POT';
vm.currentWorkspace = vm.defaultWorkspace;
vm.priorities = []; // priorities are based the names of each workspace.
// So call the workspace end point from the workspaceService
// to get a list of all workspace. Then assign it to the priorities.
vm.deliveries = {};
vm.selectTab = selectTab;
vm.retryDelivery = retryDelivery;
vm.removeDelivery = removeDelivery;
vm.downloadLog = downloadLog;
vm.getDeliveryDdex = getDeliveryDdex;
vm.refresh = refresh;
$interval(init, 5000);
return init();
/**
* Get the list of deliveries and initialize the model
*/
function init(){
deliveriesService.getDeliveries(vm.currentWorkspace).then(function (responseValues){
vm.deliveries = responseValues;
});
}
function refresh(){
init();
}
function selectTab(workspace){
vm.currentWorkspace = workspace;
init();
}

var myInterval = $interval(init, 5000);
some condition is met:
$interval.cancel(myInterval);

Related

Angular countdown service

I am trying to create an Angular service which uses a web worker to change countdown variable using set interval.
What I want to do is to show the count down in the view.
I can easily do this by putting all the code in controller, which works but I got struck in creating the service
I am struck. I dont know how to proceed.
I have tried this plunkr here
script.js
angular.module('app', []).
controller('mainCtrl', mainCtrl);
function mainCtrl($scope,timer) {
$scope.time = 100;
console.log(timer.timeValue.time);
}
mainCtrl.$inject = ['$scope','timer'];
timer.js
angular.module('app')
.service('timer', timer);
function timer() {
var time;
this.timeValue = function(value) {
var worker = new Worker('worker.js');
worker.onmessage = function(e) {
//console.log('From Main:'+ e.data.time);
time = e.data.time;
};
worker.postMessage(time);
return time;
};
}
worker.js
angular.module('app')
.service('timer', timer);
function timer() {
var time;
this.timeValue = function(value) {
var worker = new Worker('worker.js');
worker.onmessage = function(e) {
//console.log('From Main:'+ e.data.time);
time = e.data.time;
};
worker.postMessage(time);
return time;
};
}
What I want to do is like this. This is my earlier plunk.This do the same thing using controller.
plunkr here
I found out why it's not working with your code. Just for the record, a countdown is not something you want to do with a Webworker, but anyway!
First of all in timer.js:
angular.module('app')
.service('timer', timer);
timer.$inject=['$rootScope']
function timer($rootScope) {
this.timeValue = function(value) {
var time = value;
var worker = new Worker('worker.js');
worker.onmessage = function(e) {
time = e.data.time;
$rootScope.$broadcast('timerUpdate', time)
};
worker.postMessage(time);
};
}
You have to start the var time with a value.
I injected $rootScope to the service, so i can $broadcast a message back to the main scope.
In the main script I did this:
function mainCtrl($scope,timer) {
function init() {
timer.timeValue(100);
}
$scope.time = 100;
$scope.$on('timerUpdate', function(event, time) {
$scope.$apply(function() {
$scope.time = time;
})
})
init();
}
mainCtrl.$inject = ['$scope','timer'];
So, i made a Init function that gets triggered once in the beginning. That triggers your service into making a webworker.
Once the webworker gives back the message(time). The timerService sends out a $rootScope.$broadcast picked up by $scope.$on().
The $scope.$apply is not really the best thing to have in a simple script like this, but it's the only thing that will force digest(Angular page update) the page and give the $scope.time a new value.
and last the webworker:
self.onmessage = function(e) {
var time = e.data;
var timer = setInterval(toDo, 1000);
function toDo() {
time--;
postMessage({
time: time
});
}
}
(Only thing i did was change time = time - 1 to time--; (shorthand version, looks beter !)
Hope this helps !
(also, just for the record, try no to use the $rootScope or the $scope.$apply function! It's not the best way to do stuff I hear, but I'm also new to Angular and haven't found anything beter for these things..)
And the plunker:
https://plnkr.co/edit/7IoGxFaaqQRH4AErGenl?p=preview

Having an Angular $interval running independent of controller

I have different pages on may application which have their own controllers. One of them has an $interval function, let's say a timer. Click on a button will start this interval function, which updates itself every second. What i want to have is, i want to be able to go to any other page in my application (calling different controllers), but i want my interval to continue running until i stop it explicitly from the first controller. A rootScope interval so to speak. How can i do it?
EDIT: Thanks to Chris and Patrick i now have a simple Service, looks like this:
.service('TimerService', function($interval) {
var promise;
var timerSeconds = 0;
this.start = function () {
promise = $interval(function () {
timerSeconds++;
}, 1000);
};
this.stop = function () {
promise.cancel(interval);
timerSeconds = 0;
};
this.getTimer = function() {
return timerSeconds;
}
})
I store also my current value (timerSeconds) in this service. But how can i sync this value to my controller? The service increments the timerSeconds, and at the beginning of my controller i read it from this service through its getTimer() function, but it clearly will not be updated on my controller. How can i sync this service attribute with my local attribute?
EDIT:
when i define my service attribute as an object and the timerSeconds as number inside that object (it seems primitives cannot be synced):
var timer = {seconds : 0};
this.getTimer = function() {
return timer;
}
and get this object from my controller through that getter:
vm.timer = TimerService.getTimer();
they are all in sync.
Don't bother adding it to $rootScope. Use a service that can be used anywhere in the app. Here is a singleton timer that can start and stop. Define the intervalTimeout in the service itself, or if you want to be really flexible, do so in a provider (probably overkill for this example).
angular.module('myApp', [])
.service('AppCallback', function ($interval) {
var states = states = {
PENDING: 0,
STARTED: 1
}, intervalTimeout = 3000, // Set this
interval;
this.states = states;
this.state = states.PENDING;
this.start = function (callback) {
if (this.state !== states.PENDING) {
return;
}
interval = $interval(callback, intervalTimeout);
this.state = states.STARTED;
}
this.stop = function () {
if (this.state !== states.STARTED) {
return;
}
$interval.cancel(interval);
this.state = states.PENDING;
};
})
.controller('MainController', function ($scope, AppCallback) {
var vm = {},
count = 0;
vm.toggle = function toggle() {
if (AppCallback.state === AppCallback.states.PENDING) {
AppCallback.start(function () {
vm.data = 'Ticked ' + (++count) + ' times.';
});
} else {
AppCallback.stop();
}
};
$scope.vm = vm;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MainController">
{{vm.data}}
<br />
<button ng-click="vm.toggle()">Toggle</button>
</div>
If you want to share any data between controllers the correct way is to use a service.
I would then create a service that allows you to stop and start this timer / interval.
The initial controller would kick this off and it would continue to "tick" forever until it is stopped.

setInterval function only running once

I am currently playing about with the LastFM API and trying to get a Recently Played Tracks list to update as I play tracks through Spotify and ITunes. I have got the initial code working through a combination of JS and Handlebars so that a static list of tracks is loaded in on page load which is current at the time of page load.
However I want the list to update as I select a new track without refreshing the page. So I thought I could just use a setInterval function to call my original function every 5 seconds or so. However for some reason my setInterval function is only running once on page load.
I know that this is a real simple error but I can't work out why? Help!!
var clientname = {};
clientname.website = (function(){
var
initPlugins = function(){
var setupLastFM = (function(){
/* Create a cache object */
var cache = new LastFMCache(),
/* Create a LastFM object */
lastfm = new LastFM({
apiKey : '6db1989bd348bf91797bad802c6645d8',
apiSecret : '155270f02728b1936ed7699e9f7b8de9',
cache : cache
}),
attachTemplate = function(data, handlebarsTemplateID){
var template = Handlebars.compile(handlebarsTemplateID.html());
$(".container").append(template(data));
}
/* Load some artist info. */
lastfm.user.getRecentTracks({user: 'jimmersjukebox'}, {
success: function(data){
var trackData = data.recenttracks.track,
tracks = $.map(trackData, function(track) {
if(track['#attr']){
var isCurrentTrack = true;
}
return {
currenttrack: isCurrentTrack,
song: track.name,
artist: track.artist['#text']
};
});
attachTemplate(tracks, $("#trackInfo"));
}, error: function(code, message){
}}),
intervalID = window.setInterval(console.log("test"), 1000);
}());
}
return{
init: function(){
initPlugins();
}
};
})();
$(window).load(clientname.website.init);
You are running console.log("test") immediately. Try encapsulating this in anther function, but do not instantiate it by including the parenthesis ().
intervalID = window.setInterval(function(){
console.log("test");
}, 1000);
You should not call the function in setInterval. It needs a callback.
Say like bellow
intervalID = window.setInterval(function(){
console.log("test");
}, 1000);
I would recommend to use setTimeout: Use a function to contain the setTimeout, and call it within the function:
$(function() {
var current = $('#counter').text();
var endvalue = 50;
function timeoutVersion() {
if (current === endvalue) {return false;} else {
current++;
$('#counter').text(current);
}
setTimeout(timeoutVersion, 50);
}
$('a').click(function() {
timeoutVersion();
})
})​
JS Fiddle
You used a function call instead of a function reference as the first parameter of the setInterval. Do it like this:
function test() {
console.log("test");
}
intervalID= window.setInterval(test, 1000);
or you can do this also:
intervalID= window.setInterval( function() {
console.log("test!");
}, 1000);

Stop javascript counter once it reaches number specified in div

I'm using code from a JSFiddle to implement a count up feature on my site. I like it because it allows me to target a number displayed in a specific div, and I don't need to specify that number in the javascript, which means I can use it on any page for any number I choose.
See the code here:
// basic class implementation
function myCounter() {
// privileged property for iteration
this.i = 0;
// privileged init method
this.init();
}
// defining init method
myCounter.prototype.init = function () {
// reassign this
var _this = this;
setInterval(function () {
// call this.countUp() using our new created variable.
// this has to be done as this would normally call something
// inside this function, so we have to pass it as own
// variable over
_this.countUp();
}, 500);
clearInterval(function () {
this.i ==
};
};
// defining the counter method
myCounter.prototype.countUp = function () {
this.i++;
document.getElementById('counter').innerHTML = this.i;
};
// create a new instance of our counter class
var counter = new myCounter();
The only problem is that it doesn't stop counting. I'd love to add some code for that myself, except I'm not familiar enough with javascript and have no idea where to start.
Is there a way to tell javascript to stop counting at the number specified in the targeted div?
Thanks so much!
// basic class implementation
function myCounter() {
// privileged property for iteration
this.i = 0;
// privileged init method
this.init();
}
// defining init method
myCounter.prototype.init = function () {
// reassign this
var _this = this;
this.timer = setInterval(function () {
// call this.countUp() using our new created variable.
// this has to be done as this would normally call something
// inside this function, so we have to pass it as own
// variable over
_this.countUp();
}, 500);
};
// defining the counter method
myCounter.prototype.countUp = function () {
this.i++;
document.getElementById('counter').innerHTML = this.i;
// stop the timer
if(this.i == 8){
clearInterval(this.timer)
}
};
// create a new instance of our counter class
var counter = new myCounter();

javascript time event issue (setTimeout/clearTimeout)

I have always had trouble working with time events. Could someone please explain why A doesn't work and B does? The only difference is in A I put the event binding in a function. Don't worry about the function close, it has nothing to do with the question. When I test A, there is no js errors but timer is not cleared.
A ->
Test.Navigation = (function() {
var openTimer = null;
var closeTimer = null;
var addListeners = function() {
$('.hover_container').on('mousemove', function(e) {
clearTimeout(closeTimer);
});
$('.hover_container').on('mouseleave', function(e) {
// set the close timer
var container = this;
closeTimer = setTimeout(function() {
//has the mouse paused
close(container);
}, 750);
});
};
return {
init : function() {
addListeners();
}
};
})();
B ->
Test.Navigation = (function() {
var openTimer = null;
var closeTimer = null;
$('.hover_container').on('mousemove', function(e) {
clearTimeout(closeTimer);
});
$('.hover_container').on('mouseleave', function(e) {
// set the close timer
var container = this;
closeTimer = setTimeout(function() {
//has the mouse paused
close(container);
}, 750);
});
var addListeners = function() {
// nothing here
};
return {
init : function() {
addListeners();
}
};
})();
Edit: Please ignore the container part, it has nothing to dow ith the question it is simply part of the full code that I did not take out
A is binded before the object exists where the init is called. Because your return a new object. If you are using, 2 objects are created. 1 with the vars en binds. and 1 with the returns.
B is working because you create a function where the elements are initialized and use the right scope. A is not working because the bindings are on the wrong scope because your create 2 objects:
new Test.Navigation(); // Create 1 object
// Create second object.
return {
init : function() {
addListeners();
}
};
Youd better get a structure like this, then it should work aswell:
Test.Navigation = (function() {
// Private vars. Use underscore to make it easy for yourself so they are private.
var _openTimer = null,
_closeTimer = null;
$('.hover_container').on('mousemove', function(e) {
clearTimeout(_closeTimer );
});
$('.hover_container').on('mouseleave', function(e) {
// set the close timer,
// use $.proxy so you don't need to create a exta var for the container.
_closeTimer = setTimeout(
$.proxy(function() {
//has the mouse paused
close(this);
}, this)
, 750);
});
this.addListeners = function() {
// nothing here
};
this.init = function() {
this.addListeners();
}
// Always call the init?
this.init();
return this; // Return the new object Test.Navigation
})();
And use it like
var nav = new Test.Navigation();
nav.init();
Also as you can see I upgraded your code a bit. Using $.proxy, _ for private vars.
Your use of this is in the wrong scope for the first approach.
Try
var openTimer = null;
var closeTimer = null;
var self = this;
and then later
var container = self;
In your code for example A,
$('.hover_container').on('mouseleave', function(e) {
// set the close timer
var container = this;
this is actually referring to the current $('.hover_container') element.
Also, since setTimeout will wait before the previous setTimeout finishes to start again, you can get discrepancies. You may want to switch to setInterval because it will issue its callback at every interval set regardless of if the previous callback has completed.
My guess is that in the calling code, you have a statement new Test.Navigation() which, for B, addListeners is called at the time of new Test.Navigation(). In A, you return an object ref that calls an init function. Can you verify that init() is called?
I.e. in A, init() has to be called before the handlers are added. In B, the handlers are added everytime you instantiate Test.Navigation --- which, depending on the calling code, could be bad if you intend to instantiate more than one Test.Navigation() at a time.

Categories

Resources