I tried to set up a simple app to show the latest message of each member.
At first, it loads the members array.Then I call a function refreshMsg to loop through the array.
Within the loop, I set an timer on it.
However it did not work at all.Could someone five me an hint?
Many thanks.
demo
//show the message for each member and set an timer to refesh
function refreshMsg(){
//loop through members array and set a timer
for(var i=0;i<$scope.members.length;i++){
var cur_member=$scope.members[i];
var name = cur_member.name;
var url_getMsg = "api/getMsg/".name;
var timer = $timeout( function refresh(){
$http.get(url_getMsg).success(function(data){
cur_member.msg=data;
}
)
timer = $timeout(refresh, 3000);
}, 3000);
}
}
})
One of the reasons it is not working correctly is that due to async nature of the call the cur_member would not match the response message as the loop would have moved ahead. The way to do this would be to create another method specifically for setting the $timeout which would create a closure. Better still use $interval
function refreshMsg(){
//loop through members array and set a timer
for(var i=0;i<$scope.members.length;i++){
var cur_member=$scope.members[i];
var name = cur_member.name;
setupRefresh(curr_member);
}
function setupRefresh(member) {
var url_getMsg = "api/getMsg/"+member.name;
var timer = $interval( function(){
$http.get(url_getMsg).success(function(data){
member.msg=data;
}
);
}, 3000);
}
Also remember to dispose all the interval when scope is destroyed.
Related
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();
}
})
I am new to GeoFire, FireBase and Angular. I am trying to create a function that will take some coordinates and return some objects in vicinity of those coordinates.
I return a promise from the function which I assign to a scope variable used in the view hoping that when the promise is resolved by the ready event the array of objects in vicinity will be available.
obj.findGroupsInViscinity = function(pos){
var gFire = factoryAuth.geoFire;
var fbaseRef = factoryAuth.usersRef;
var groupsInQuery = {};
var groupsInQueryAr = [];
var deferred = $q.defer();
var geoQuery = gFire.query({
center: [pos.coords.latitude, pos.coords.longitude],
radius: 2
})
geoQuery.on("key_entered", function(groupId, groupLocation, distance) {
console.log("--> key_entered 1");
groupsInQuery[groupId] = true;
// Look up the vehicle's data in the Transit Open Data Set
fbaseRef.child("groups").child(groupId).once("value", function(dataSnapshot) {
console.log("--> key_entered 2");
// Get the vehicle data from the Open Data Set
group = dataSnapshot.val();
// If the vehicle has not already exited this query in the time it took to look up its data in the Open Data
// Set, add it to the map
if (group !== null && groupsInQuery[groupId] === true) {
console.log("Adding group", group);
// Add the group to the list of groups in the query
groupsInQuery[groupId] = group;
groupsInQueryAr.push({"name": group.name});
}
})
}) // end ke_entered monitoring
geoQuery.on("ready", function() {
console.log("GeoQuery ready event received. groupsInQueryAr = ", groupsInQueryAr);
deferred.resolve(groupsInQueryAr);
geoQuery.cancel();
console.log("GeoQuery canceled");
}) // Cacnel the geoQuery once we have gotten all the groups in viscinity
return deferred.promise; // Return a promise that will be resolved when ready event fires
}
Included below the console output from calling this function.
What I notice is that the key_entered part of the code is called twice in succession but before the code to process the key_entered event completes, the ready event is called because all key_entered events have fired. So while the key_entered part of the logic is building out the array I want to pass in resolving the promise, it is not ready at the time I resolve the promise in the ready event.
How can I ensure that I resolve the promise after all key_entered events have been processed and my array of objects has been built out properly?
Thanks,
Sanjay.
I would say that this is a bit of an XY problem and I would suggest you just load the restaurants into your view as you get them. This will probably be a better user experience in most cases.
That being said, if you want to do what you are asking about, you can make it work by using $.all(). Essentially, create and return your deferred promise. Start with an empty list and for every key_entered event, push a new promise onto the list. Then, in your ready event callback, do a $q.all() on the list of promises and once they complete (in the then() of the promise), do the deferred.resolve().
I have this bit of code to start invoke an interval:
// Start timer function
var startTimer = function () {
// Apply our first image
applyImage(element);
console.log('about to start the timer');
console.log(timer);
// If our timer is not running
if (!timer) {
console.log('start timer');
// Start our timer
timer = $interval(changeImage, 10000);
}
};
One thing I am doing there is checking to see if the timer is anything other than null / undefined.
But I have noticed that when I call my stop function:
var stopTimer = function () {
console.log('about to stop the timer')
// If we have started our timer
if (timer) {
console.log('stop timer');
// Stop it
$interval.cancel(timer);
}
};
It does not actually clear timer it just sets the status to 'cancelled'.
After I call $interval.cancel(timer) can I set timer to null?
Or should I change my start function to something like this:
// Start timer function
var startTimer = function () {
// Apply our first image
applyImage(element);
console.log('about to start the timer');
console.log(timer);
// If our timer is not running
if (!timer || timer.$$state.status === 2) {
console.log('start timer');
// Start our timer
timer = $interval(changeImage, 10000);
}
};
You can absolutely set timer to null at that point... or you can delete it. The cancel call can't delete the var from the caller's scope - JavaScript doesn't have a mechanism to do this. Marking it cancelled also gives you control over what happens next, such as if you were running half a dozen intervals and needed to keep track of their states for some reason.
Note that there is a difference between delete and setting to null. Null is a perfectly legitimate value in JavaScript so setting a var to null doesn't actually indicate that it's "no longer needed" the way some people expect. The object referenced can be freed (if this was the last reference to it) but the var itself will still exist in scope.
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());
}
I'm using ExtJS 4 MVC.
Is there a way to reload Store every X seconds?
I'd like to put code somewhere to Controller.
setInterval(function(){
// Use Ext.getStore to reference your store from the controller
var myStore = Ext.getStore('YourStore');
// Pass in an object of the changes you want to be made to the store
myStore.proxy.extraParams = { key:'sencha'}; // replace with your own object
myStore.load();
},3000);
FYI in Extjs this is possible to implement via Ext.util.TaskRunner.
A sample code:
var runner = new Ext.util.TaskRunner(),
clock, updateClock, task;
clock = Ext.getBody().appendChild({
id: 'clock'
});
// Start a simple clock task that updates a div once per second
updateClock = function() {
clock.setHtml(Ext.Date.format(new Date(), 'g:i:s A'));
};
task = runner.start({
run: updateClock,
interval: 1000
});