The interval function keeps on looping in the last element that I click. What I want to happen is to cancel the last interval when I click on a new element and start all over again when I click it. I clicking on each item in ng-repeat.
This is my code.
$scope.onClickTab= function(x,tkid, sid, $event){
var vtpostdata = 'TokenId=' + tkid +
',SessionId=' + sid +
',ChatMessageCount=' + 0 +
',retrytimes=' + 10 +
',delayms=' + 100;
$interval(function() {
$http.jsonp(ServiceDomainSite + 'myApi' + vtpostdata + '?callback=JSON_CALLBACK&t='
+ new Date().getTime())
.success(function (data) {
var resultObject = angular.fromJson(data.Rows);
$scope.Chats = resultObject;
});
}, 1000);
};
Nice and fine with $interval.cancel(). I also removed var vtpostdata because it is not used in the code untill your $http request again. So there is no need to create a var at this point. Also check the documentation of AngularJS $interval to learn more about $interval handling.
var myInterval = null;
$scope.onClickTab = function(x,tkid, sid, $event){
//cancel current interval
if (myInterval !== null) {
$interval.cancel(myInterval);
}
myInterval = $interval(function() {
$http.jsonp(ServiceDomainSite + 'myApiTokenId=' + tkid +
',SessionId=' + sid +
',ChatMessageCount=' + 0 +
',retrytimes=' + 10 +
',delayms=' + 100 + '?callback=JSON_CALLBACK&t='
+ new Date().getTime()).success(function (data) {
var resultObject = angular.fromJson(data.Rows);
$scope.Chats = resultObject;
});
}, 1000);
};
$interval service returns a promise which can be canceled at any time so you can use them as per official documentation. For Eg.
var stopTime = $interval(function(){}, 1000);
and for canceling just use
$interval.cancel(stopTime);
https://docs.angularjs.org/api/ng/service/$interval
Related
I'm using AngularJS to prefetch images in cache client and then I want to animate those prefetched images.
My code for the prefetching:
$scope.prefetch=function(limit) {
for (var i=0; i<limit; i++) {
var date = new Date($scope.dt);
if ($scope.fileFlag == false) {
if ($scope.viewmodel.timeResolution == 'yearly')
date = new Date(date.setFullYear(date.getFullYear() + i));
else if ($scope.viewmodel.timeResolution == 'monthly')
date = new Date(date.setMonth(date.getMonth() + i));
else if ($scope.viewmodel.timeResolution == 'daily') {
date = new Date(date.setDate(date.getDate() + i));
}
} else {
date = $scope.files[$scope.files.indexOf($scope.idSelectedVote) + i];
}
console.log( $http.get(site_url + "mwf/" + $scope.viewmodel.dataSet + "/" + $scope.viewmodel.varName + "/" + $scope.viewmodel.region + "/" + date + "/map/?vMin=" + $scope.VMin + "&vMax=" + $scope.VMax + "&type=" + $scope.viewmodel.type + "&cmap=" + $scope.viewmodel.colorMap, {'cache': true}));
}
};
then i do something like this to play those images
$scope.play=function(limit) {
for (var i=0; i<limit; i++) {
$scope.map.src= site_url + "mwf/" + $scope.viewmodel.dataSet + "/" + $scope.viewmodel.varName + "/" + $scope.viewmodel.region + "/" + parseInt(date)+i + "/map/?vMin=" + $scope.VMin + "&vMax=" + $scope.VMax + "&type=" + $scope.viewmodel.type + "&cmap=" + $scope.viewmodel.colorMap;
$scope.sleepFor(500);
}
};
$scope.sleepFor = function( sleepDuration ) {
var now = new Date().getTime();
while(new Date().getTime() < now + sleepDuration){ /* do nothing */ }
}
My problem is when I call play(4) it displays only the first and the last images and not an animation. Any idea on how can I improve this code or a different approach so I can do this?
Your sleepFor is an idle loop: you spin and do nothing, but you prevent any other work from being done. This is not the way in Javascript to delay work for a set period of time, or schedule a function to be run at a later time. In Javascript we use window.setTimeout -- and in Angular we have the convenient $timeout service to provide that:
$scope.play = function(limit) {
for (var i=0; i < limit; i++) {
$scope.map.src = site_url + "mwf/" + $scope.viewmodel.dataSet + "/" + $scope.viewmodel.varName + "/" + $scope.viewmodel.region + "/" + parseInt(date)+i + "/map/?vMin=" + $scope.VMin + "&vMax=" + $scope.VMax + "&type=" + $scope.viewmodel.type + "&cmap=" + $scope.viewmodel.colorMap;
var nextFrameMs = 500;
$timeout($scope.play, nextFrameMs);
}
};
In your example, wherever your $scope is provided to you -- assuming this is in a controller, you will have some line like module.controller($scope, ...) -- you will have to inject the $timeout service to be able to use it.
Additional resources:
Angular's documentation on $timeout
MDN documentation of window.setTimeout
You have to use intervals otherwise your code will block the execution of other code
Using Angular's built in $interval service is the solution:
var playInterval;
$scope.play = function(limit) {
var interval = 1000 / 20; //20 frames per second
var i = 0;
$interval.cancel(playInterval); //stop previous animations if any
if(i < limit) {
$scope.map.src = getSrc(i++);
var cache = $interval(function() {
if(i >= limit) {
return $interval.cancel(playInterval); //or you can replace with `i = 0;` to loop the animation
}
$scope.map.src = getSrc(i++);
}, interval);
}
};
function getSrc(i) {
return site_url + "mwf/" + $scope.viewmodel.dataSet + "/" + $scope.viewmodel.varName + "/" + $scope.viewmodel.region + "/" + parseInt(date)+i + "/map/?vMin=" + $scope.VMin + "&vMax=" + $scope.VMax + "&type=" + $scope.viewmodel.type + "&cmap=" + $scope.viewmodel.colorMap;
}
So I have this code that I am running inside of the google chrome console, and every time that I try to run it it give me unexpected identifier on line: 12. I went to that line and it is the setTimeout. I really don't know how to fix this, I tried to just call snipebot() but that didn't work either.
function snipebot(itemID, max_price){
var ItemURL = "http://www.roblox.com/Item.aspx?id=" + itemID;
$.get(ItemURL, function(data){
var purchaseData = $($(data).find(".PurchaseButton")[0]).data();
if (purchaseData['expectedPrice'] <= max_price){
$.post('/API/Item.ashx?rqtype=purchase&productID=' + purchaseData['productId'] + '&expectedCurrency=1&expectedPrice=' + purchaseData['expectedPrice'] + '&expectedSellerId=' + purchaseData['expectedSellerId'] + '&userAssetID=' + purchaseData['userassetId'], function(){
console.log('[' + purchaseData['expectedPrice'] + ']');
});
}
}
setTimeout(function(){
snipebot(itemID, max_price);
});
};
snipebot(18426536, 140);
It's unexpected because your call to $.get hasn't been closed properly on the previous line:
function snipebot(itemID, max_price){
var ItemURL = "http://www.roblox.com/Item.aspx?id=" + itemID;
$.get(ItemURL, function(data){
var purchaseData = $($(data).find(".PurchaseButton")[0]).data();
if (purchaseData['expectedPrice'] <= max_price){
$.post('/API/Item.ashx?rqtype=purchase&productID=' + purchaseData['productId'] + '&expectedCurrency=1&expectedPrice=' + purchaseData['expectedPrice'] + '&expectedSellerId=' + purchaseData['expectedSellerId'] + '&userAssetID=' + purchaseData['userassetId'], function(){
console.log('[' + purchaseData['expectedPrice'] + ']');
});
}
}); // <-- here
setTimeout(function(){
snipebot(itemID, max_price);
}, 2000); // <!-- See below
};
snipebot(18426536, 140);
Also note my second comment, where you've missed the 2nd parameter to setTimeout, namely how long to delay for. I've added in a two second delay as an example. Without this, it defaults to 0, which may or may not be what you intended.
I'm looping through an array an show the data on my screen. This part is working perfectly.
Now I want to sorting the elements on 'Startdate'.
for (var i = 0; i < schedule_id.length; i++) {
//Ajax call maken
$.ajax({
url: "http://api.viewer.zmags.com/schedules/" + schedule_id[i] + "?key=" + api_key
})
//WdInit after 10 calls
.done(function(data){
//Check publicatieID is not null
if (undefined === data.scheduleEntries[default_pub]|| null === data.scheduleEntries[default_pub]) {
}
else
{
//loopen doorheen resultaat call
$.each(data.scheduleEntries, function(index, entry){
//Datums
var sdate = moment(entry.startDate).format('DD/MM');
var edate = moment(entry.endDate).format('DD/MM');
var sdatecheckformat = moment(entry.startDate).format('YYYY/MM/DD');
var edatecheckformat = moment(entry.endDate).format('YYYY/MM/DD');
var sdatecheck = new Date(sdatecheckformat);
var edatecheck = new Date(edatecheckformat);
var today = new Date();
var timeDiff = Math.abs(sdatecheck.getTime() - today.getTime());
var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24));
//Check geldig
if(today<=edatecheck && diffDays<=14){
// Decide list order, load the thumbnail for each publication.
var place = "first";
$('#archive').prepend('<div class="container" id="'+entry.publicationID+'"></div>');
$('.container:' + place).append('<div class="thumb"></div>');
$('.thumb:' + place).css("background-image", 'url(' + entry.thumbnailURL + ')');
$('.thumb:' + place).css("filter", 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=' + entry.thumbnailURL + ',sizingMethod="scale")');
$('.thumb:' + place).css("-ms-filter", 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=' + entry.thumbnailURL + ',sizingMethod="scale")');
// Load the publication title below each thumbnail.
$('.thumb:' + place).after('<div class="title"></div>');
$('.title:' + place).append(entry.publicationName);
// Load the publication startsdate & enddate.
$('.title:' + place).after('<div class="date"></div>');
$('.date:' + place).append(sdate + " tot " + edate);
// Set up publication links.
$('.container:' + place).click(function(){
loadPub(entry.publicationID, entry.publicationName);
setActive(entry.publicationID);
//Change css of current element
});
}
//Eerste element tonen
if(0===first_element){
first_element++;
loadPub(entry.publicationID, entry.publicationName);
initFirst(entry.publicationID);
}
});
}
});
//Einde loop
}
Within this loop it is not possible to sort because we are writing the element immediately. Can you please help me a way to sort the data. Maybe getting all data first and sorting them by creating an array with the same schedules ID's but in a correct sorted way.
My code so far:
//Sortering
var arr = [];
var arr1 = [];
//Loopen 10 keer
for (var i = 0; i < schedule_id.length; i++) {
arr1.push("test");
//Ajax call maken
$.ajax({
url: "http://api.viewer.zmags.com/schedules/" + schedule_id[i] + "?key=" + api_key,
success: function(data) {
arr.push(data);
}
})
}
//Know looping throught array or something and sorting
You can use $.when() to wait for multiple deferreds to resolve.
For example:
var arrayOfAjaxPromises = [$.ajax("/page1"), $.ajax("/page2"), $.ajax("/page3")];
$.when.apply($, arrayOfAjaxPromises).done(function() {
// this callback gets called when all the promises are resolved
// responses are passed in the array-like arguments object, so they can be read sequentially
// or you can sort or process the way you want
var i;
for (i = 0; i < arguments.length; i+= 1) {
alert(arguments[i]);
}
});
I have this code so far...
function sendData() {
// this work out where I am and construct the 'cmi.core.lesson.location' variable
computeTime();
var a = "" + (course.length - 1) + "|";
for (i = 1; i < course.length; i++) {
a = a + qbin2hex(course[i].pages).join("") + "|";
if (iLP == 1) {
a = a + course[i].duration + "|";
a = a + course[i].timecompleted + "|"
}
}
SetQuizDetails();
a = a + course[0].quiz_score_running + "|0|0|0|0|0|0|";
objAPI.LMSSetValue("cmi.core.lesson_location", "LP_AT7|" + a);
bFinishDone = (objAPI.LMSCommit("") == "true");
objAPI.LMSCommit("");
console.log("Data Sent!");
}
setTimeout(sendData(), 1000);
However, it doesn't seem to work as intented. Data should be sent off to the server every 1000ms, but that's not happening. What am I missing here?
As I side note, this is SCORM 1.2.
So, you're calling
setTimeout(sendData(), 1000);
which is equivalent to
var foo = sendData();
setTimeout(foo, 1000);
seeing as sendData returns nothing, this becomes equivalent to
setTimeout(undefined, 1000);
you probably meant:
setTimeout(sendData, 1000);
I'm working in an script which contains a function that needs to be called at every 10 minutes. Also, to inform the user of how many time is left before reloading of the function (via AJAX, but this is not relevant now), I put a little regressive timer.
This is the main structure:
$(document).ready(function () {
// Test's function
function loadDate() {
var myDate = new Date();
$("#dateload").html(myDate);
};
// Startup Variables
countermin = 10; // 10 minutes
countersec = 60;
minpass = 0;
secpass = 0
// Showing info before timer.
$("#reloadtime").html("Function will be reloaded in " + countermin + "m<b>" + (60 - countersec) + "</b>s<br/>(countersec's value: " + countersec + " - secpass' value: " + secpass + ")");
$("#timescalled").text("The date function has been called " + minpass + " times after page's load.");
loadDate();
// FIRST setInterval
// It's our timer.
intvl1 = setInterval(function () {
if (countersec++ == 60) {
countermin--;
countersec = 1;
}
if (countermin < 0) {
countermin = 9;
countersec = 1;
secpass = 0;
}
secpass++;
$("#reloadtime").html("Function will be reloaded in " + countermin + "m<b>" + (60 - countersec) + "</b>s<br/>(countersec's value: " + countersec + " - secpass' value: " + secpass + ")");
}, 1000);
// SECOND setInterval
// Counting 10 minutes to execute the function again (and again...).
intvl2 = setInterval(function () {
minpass++;
$("#minpass").text("The date function has been called " + minpass + " times after page's load.");
loadDate();
}, 600000);
});
My problem is: both timers are not synchronized. The intvl2 is executing the function and going back before the timer (intvl1) reaches 0. The error is about 20 seconds, increasing after each 10 minutes.
If you compare with the time printed on beginning, around 6, 7 minutes of execution you can see difference with in the times, when comparing with your PC's clock.
How can I get them synchronized?
You can check this fiddle.
A simpler approach would be to use a single timer that does both things, updates the countdown information and triggers the event. Below is an example:
var oneSecond = 1000;
var counter = 0;
var eventInterval = 5 * oneSecond;
var timesTriggered = 0;
setInterval(function () {
counter = (counter + oneSecond) % eventInterval;
$('.countdown').text((eventInterval - counter) / oneSecond);
if(counter == 0){
timesTriggered++;
$('.timesTriggered').text(timesTriggered);
}
}, oneSecond);
Working fiddle: http://jsfiddle.net/TFDSU/3/
I've hacked about with your code a bit - I can't sit through a 10 minute countdown :) so I switched it to a minute and some other changes but this is working fine and not losing time..
$(document).ready(function () {
// Function of Test
function loadDate() {
var myDate = new Date();
$("#dateload").html(myDate);
};
countersec = 60; //
minpass = 0;
$("#reloadtime").html("Function will be reloaded in "+countersec+"</b>s<br/>");
$("#timescalled").text("The date function has been called " + minpass + " times after page's load.");
loadDate();
intvl1 = setInterval(function () {
countersec--;
if (!countersec) { countersec=60; }
$("#reloadtime").html("Function will be reloaded in "+countersec+"</b>");
}, 1000);
intvl2 = setInterval(function () {
minpass++;
$("#minpass").text("The date function has been called " + minpass + " times after page's load.");
loadDate();
}, 60000);
});