I would like to delay the for loop process so that the loading of data looks like a progress bar.
In this code, the moment i click the button, it will directly display this data: 20/20 Records Rendered.
I would like to see the record start with 1/20 Records Rendered then after 3 seconds it will become 2/20 Records Rendered and so on.
Here is the code:
<button name="subject" type="submit" value="6" onClick="Run(this.value)">Run</button>
<script>
function Run(value) {
custRecordsRendered = 0;
$.ajax({
type: 'Post',
url: "/Tasks/RunSample",
success: function (data) {
totalRecords = data[0].Total;
console.log("Total: " + data[0].Total);
console.log("Records: " + Object.keys(data).length);
for (var key in data) {
(function iterator() {
console.log("logs: "+data[key].Records);
setTimeout(iterator, 3000);
})();
if (data.hasOwnProperty(key)) {
custRecordsRendered = data[key].Records;
updateProgress();
}
}
}
});
function updateProgress() {
$("#completeCount").text(custRecordsRendered + "/" + totalRecords + " Records Rendered");
}
}
</script>
Controller:
public JsonResult RunSample()
{
List<object> countData = new List<object>();
int count = 20;
for (int i = 1; i <= count; i++)
{
countData.Add(new { Total = count, Records = i });
}
return Json(countData);
}
Thank you for helping me.
if I got what you mean correctly .. this code may do the trick
function Run(value) {
custRecordsRendered = 0;
$.ajax({
type: 'Post',
url: "/Home/RunSample",
success: function (data) {
totalRecords = data[0].Total;
console.log("Total: " + data[0].Total);
console.log("Records: " + Object.keys(data).length);
var itemCount = 0;
var progressInterval = setInterval(function () {
if (itemCount < data.length) {
console.log(itemCount);
console.log("logs: " + data[itemCount].Records);
custRecordsRendered = data[itemCount].Records;
updateProgress();
itemCount++;
}
else {
clearInterval(progressInterval);
}
}, 500);
}
});
function updateProgress() {
$("#completeCount").text(custRecordsRendered + "/" + totalRecords + " Records Rendered");
}
}
in your code you are treating the setTimeout function as if it causes the Thread to sleep but actually, it does not what it does is setting a delayed asynchronous event that will be fired after the specified interval and execute the handler function, but the execution of the code which is after the setTimeout call will continue .. so setInterval will serve the purpose for you
Related
I am having some problem using the settimeout() in my function. I am new to async. No matter how much I try I just can't make the timeout work. My code works perfect so that is not the problem. I need the request to execute every 10 seconds. Thanks for the help.
function getContent() {
function getPelicula(pelicula, donePelicula) {
var peli = pelicula.title;
//request id
request({
url: "http://api.themoviedb.org/3/search/movie?query=" + peli + "&api_key=3e2709c4c051b07326f1080b90e283b4&language=en=ES&page=1&include_adult=false",
method: "GET",
json: true,
}, function(error, res, body) {
if (error) {
console.error('Error getPelicula: ', error);
return;
}
var control = body.results.length;
if (control > 0) {
var year_base = pelicula.launch_year;
var id = body.results[0].id;
var year = body.results[0].release_date;
var d = new Date(year);
var year_solo = d.getFullYear();
if (year_base == year_solo) {
pelicula.id = id;
pelicula.year_pagina = year_solo;
}
} else {
pelicula.id = null;
pelicula.year_pagina = null;
}
donePelicula();
});
}
}
To do something in a loop, use setInterval.
UPD:
In general, there're two ways of executing some code in loop
1 setTimeout :
var someTimer = setTimeout(function sayHello(){
console.log("hello!");
someTimer = setTimeout(sayHello, 2000);
}, 2000);
Notice that someTimer variable is needed to stop the looping process if you need: clearTimeout(someTimer)
2 setInterval:
var someIntervalTimer = setInterval(function(){
console.log("I'm triggered by setInterval function!");
}, 2000);
Invoke clearInterval(someIntervalTimer) to stop the looping
Both functions are treated as properties of the global Window variable. By default, the following code works:
var window = this;
console.log("type of setTimeout: " + typeof window.setTimeout);
console.log("type of setInterval: " + typeof window.setInterval);
Try putting it in another function so:
domore(pelicula,donePelicula);
function domore(pelicula,donePelicula) {
// 1 second
var timeout = 1000;
for (var i = 1; i < pelicula.length; i++) {
createData(pelicula[i],donePelicula,timeout);
timeout = timeout + 800;
}
}
function createData(peli,donePelicula,timeout) {
setTimeout(function() { getData(peli,donePelicula); }, timeout);
}
function getData(peli,donePelicula) {
var txtFile = new XMLHttpRequest();
txtFile.open("GET", "http://api.themoviedb.org/3/search/movie?query=" + peli + "&api_key=3e2709c4c051b07326f1080b90e283b4&language=en=ES&page=1&include_adult=false", true);
txtFile.onreadystatechange = function() {
if (txtFile.readyState === 4) { // Makes sure the document is ready to parse.
if (txtFile.status === 200) { // Makes sure it's found the file.
allText = txtFile.responseText;
domore(allText,donePelicula);
}
}
}
txtFile.send(null);
}
I am trying to call the function which posts the ajax request to check the database, every 10 seconds to see if the required information I want has arrived or not, if the required information has not arrived for 60 seconds, I just want to exit the function.
The problem I am having right now is that, my function doesnt call self.startInstantorCheck every 10 seconds, and then exits to the end after 60 seconds.
Here is the function
self.startInstatorCheck = function(){
self.instatorStarts(true);
var MAX_WAIT_TIME_MS = 1 * 60 * 1000;
var POST_INTERVAL_MS = 10 * 1000;
var timeoutTime = null;
$.ajax({
type: 'POST',
url: BASEURL + 'index.php/moneyexchange/check_instantor_field/' + auth,
contentType: 'application/json; charset=utf-8'
})
.done(function(userinfo) {
if (timeoutTime == null) {
// Start of the timeout cycle:
timeoutTime = Date.now() + MAX_WAIT_TIME_MS;
}
if (userinfo.instantor_request > 12) {
self.allInstantorCheckMessages('Instantor data gathered');
} else {
if (Date.now() < MAX_WAIT_TIME_MS) {
setTimeout(self.startInstatorCheck(), POST_INTERVAL_MS);
} else {
self.allInstantorCheckMessages('Please go through instantor to ');
self.instatorStarts(true);
self.magicInstantorbtn2(true);
}
}
})
.fail(function(jqXHR, textStatus, errorThrown) {
self.errorMessage(errorThrown);
})
.always(function(data){
});
}
I am using knockout js, so would be great if the answers or help are related to knockout js.
First of all, here's your code simplified to reduce nesting and provide clarity through naming.
self.startInstatorCheck = function(){
self.instatorStarts(true);
var MAX_WAIT_TIME_MS = 1 * 60 * 1000;
var POST_INTERVAL_MS = 10 * 1000;
var timeoutTime = null;
$.ajax({
type: 'POST',
url: BASEURL + 'index.php/moneyexchange/check_instantor_field/' + auth,
contentType: 'application/json; charset=utf-8'
})
.done(function(userinfo) {
// please use === not ==
// == doesn't always do what you want it to do, NEVER use it
timeoutTime = timeoutTime === null ?
Date.now() + MAX_WAIT_TIME_MS :
timeoutTime;
var pleaseNameMe = userinfo.instantor_request > 12
if (pleaseNameMe) {
return self.allInstantorCheckMessages('Instantor data gathered');
}
var expired = Date.now() < MAX_WAIT_TIME_MS
if (!expired) {
return setTimeout(self.startInstatorCheck(), POST_INTERVAL_MS);
}
self.allInstantorCheckMessages('Please go through instantor to ');
self.instatorStarts(true);
self.magicInstantorbtn2(true);
})
.fail(function(jqXHR, textStatus, errorThrown) {
self.errorMessage(errorThrown);
})
.always(function(data){
});
}
Secondly, your question has been solved before, knockoutjs or not. Here is a wonderful article that explains how to do polling in javascript using timeout. It recommends using promises. I strongly agree. (They can and should be used in conjunction with knockout js.) A contrived example directly from the blog:
// The polling function
function poll(fn, timeout, interval) {
var dfd = new Deferred();
var endTime = Number(new Date()) + (timeout || 2000);
interval = interval || 100;
(function p() {
// If the condition is met, we're done!
if(fn()) {
dfd.resolve();
}
// If the condition isn't met but the timeout hasn't elapsed, go again
else if (Number(new Date()) < endTime) {
setTimeout(p, interval);
}
// Didn't match and too much time, reject!
else {
dfd.reject(new Error('timed out for ' + fn + ': ' + arguments));
}
})();
return dfd.promise;
}
// Usage: ensure element is visible
poll(function() {
return document.getElementById('lightbox').offsetWidth > 0;
}, 2000, 150);
there are few mistakes in your code.
compare this with yours to see the changes
self.startInstatorCheck = function() {
self.instatorStarts(true);
var t = new Date();
var timeoutTime = t.setSeconds(t.getSeconds() + 60)
var interval = 10 * 1000;
function instatorCheck() {
$.ajax({
type: 'POST',
url: BASEURL + 'index.php/moneyexchange/check_instantor_field/' + auth,
contentType: 'application/json; charset=utf-8'
})
.done(function(userinfo) {
if (userinfo.instantor_request > 12) {
self.allInstantorCheckMessages('Instantor data gathered');
} else {
if (new Date() < timeoutTime) {
setTimeout(instatorCheck, interval);
} else {
self.allInstantorCheckMessages('Please go through instantor to ');
self.instatorStarts(true);
self.magicInstantorbtn2(true);
}
}
})
.fail(function(jqXHR, textStatus, errorThrown) {
self.errorMessage(errorThrown);
})
.always(function(data) {});
}
instatorCheck();
}
I have this source:
$("#allDataForm").submit( function (e) {
e.stopPropagation();
var formData = $("#allDataForm").serialize();
var count = formData.substring(formData.indexOf('&count=')+7,formData.indexOf('&x='));
var x = parseInt(formData.substring(formData.indexOf('&x=')+3, formData.length));
if (formData.indexOf('=description&') > 0 &&
formData.indexOf('=name&') > 0 &&
formData.indexOf('=identifier&') > 0) {
var head = 0;
if (formData.indexOf('firstashead=on') > 0) {
head=1;
}
head = parseInt(head);
var imported = 0;
var updated = 0;
$("#assignTable").hide();
$("#send").hide();
$("#status").show();
var totalTime = 0;
if (count > 0) {
for (s=x; s<=count; s++) {
var startms = new Date().getTime();
$.ajax({
type: "POST",
data: formData,
dataType: "html",
url: "/import/universalimport/",
async: false,
success: function(msg, textStatus, XMLHttpRequest) {
console.log($.makeArray(arguments), 'success');
console.log(textStatus, 'success1');
console.log(XMLHttpRequest, 'success2');
if (msg == 'imported') {
imported = parseInt(imported)+1;
} else if (msg == 'updated') {
updated = parseInt(updated)+1;
}
var endms = new Date().getTime();
totalTime = totalTime + (endms-startms);
x = totalTime / 1000;
tSeconds = Math.abs((x % 60).toFixed(0));
if (tSeconds < 10) {
tSeconds = 0+String(tSeconds);
}
x /= 60;
tMinutes = Math.abs((x % 60).toFixed(0));
if (tMinutes < 10) {
tMinutes = 0+String(tMinutes);
}
x /= 60;
tHours = Math.abs((x % 24).toFixed(0));
if (tHours < 10) {
tHours = 0+String(tHours);
}
x = (totalTime*(count-s-head)/s) / 1000;
aSeconds = Math.abs((x % 60).toFixed(0));
if (aSeconds < 10) {
aSeconds = 0+String(aSeconds);
}
x /= 60;
aMinutes = Math.abs((x % 60).toFixed(0));
if (aMinutes < 10) {
aMinutes = 0+String(aMinutes);
}
x /= 60;
aHours = Math.abs((x % 24).toFixed(0));
if (aHours < 10) {
aHours = 0+String(aHours);
}
eval($("#bar").css('width', (parseInt(s)/parseInt(count)*100).toFixed(2) + '%'));
$("#bar").html((parseInt(s)/parseInt(count)*100).toFixed(2) + '%');
$("#imported").html(imported);
$("#updated").html(updated);
$("#summary").html(imported+updated);
$("#count").html(count-head);
$("#elapsed").html(tHours + ':' + tMinutes + ':' + tSeconds);
$("#remaining").html(aHours + ':' + aMinutes + ':' + aSeconds);
formData = formData.substring(0, formData.indexOf('&x=')+3) + parseInt(s);
}
});
}
}
} else {
alert('Pro provedení importu je nutno napárovat minimálně Název, Popis a Identifikátor!');
}
return false;
});
In Google Chrome it wont evaluate script inside success immediately but after all ajax calls it execute the last one. When I add alert() inside success it works fine and in Firefox it works well.
Async is a depreciated feature. Success is also on its way out. You should be using
$.ajax({
type: "POST",
data: formData,
dataType: "html",
url: "/import/universalimport/"
}).done(msg, textStatus, XMLHttpRequest) {
... rest of code when done here
Here is a jsfiddle showing a set of $.ajax() POSTs being sent all at once and coming back at different intervals:
<ul id='log'></ul>
<script>
var call,
log = $('#log');
for (call = 0; call < 10; call++) {
$.ajax({
type: 'POST',
url: '/echo/html/',
data: {
html: "ajax response #" + call,
delay: 3
},
success: function(data) {
log.append('<li>'+data+'</li>')
console.log(data);
},
dataType: 'html'
});
log.append('<li>'+('ajax request #' + call)+'</li>')
console.log('ajax request #' + call);
}
</script>
I've run this in Chrome and Firefox and the behavior appears to be the same (the ajax responses return out of order as though they had been submitted at different intervals). Does this model the problem you are talking about?
Solved by recursive calling asynchronous ajax. Thanks for help.
I need to be able to call a function getProgress every second. This function does an ajax request and updates a progress bar. I need to be able to stop the call to this function when a call returned from ajax is "true".
Html:
<td class="checkbox">
<input type="checkbox" value="6" class="checkbox download" id="chk-6">
<div class="hide" id="prgbar-6"><span class="progresslabel"></span></div>
</td>
My function:
function getProgress(operationId) { // receives operationId
$.post("#Url.Action("Status","Packages")", { operationId: operationId }, function (data) {
if (data) {
for (var key in data) {
if ($("#prgbar-" + key + "").size() != 0) {
var objPrg = $("#prgbar-" + key + "");
var objchk = $("#chk-" + key + "");
if (data[key]) {
objPrg.find("span").text("downloading...").css("color:#000000");
objchk.hide();
objPrg.removeClass("hide").show().progressbar({
value: 0
});
var value = Math.floor(parseInt(data[key]) * 100);
objPrg.progressbar("option", "value", value);
objPrg.find("span").text(value + "%");
} else {
}
}
}
}
});
}
var interval = setInterval(function(){getProgress(operationId,interval)},1000);
In your $.POST complete callback function, clear this interval: {i use complete here but if you want to do only for successful request, use .success()}
$.post("#Url.Action("Status","Packages")", { operationId: operationId }, function (data) {
if (data) {
for (var key in data) {
if ($("#prgbar-" + key + "").size() != 0) {
var objPrg = $("#prgbar-" + key + "");
var objchk = $("#chk-" + key + "");
if (data[key]) {
objPrg.find("span").text("downloading...").css("color:#000000");
objchk.hide();
objPrg.removeClass("hide").show().progressbar({
value: 0
});
var value = Math.floor(parseInt(data[key]) * 100);
objPrg.progressbar("option", "value", value);
objPrg.find("span").text(value + "%");
} else {
}
}
}
}
}).complete(function() { clearInterval(interval); });
I like this method. It requires no clearing of intervals. It just runs on its own and sets a timeout if necessary.
var operationId = ...;
var processFunction = function () {
$.post("#Url.Action("Status","Packages")", { operationId: operationId }, function (data) {
if (data !== true) {
// your normal function stuff
setTimeout(processFunction, 1000);
}
});
};
setTimeout(processFunction, 1000);
Method #1:
You could just make a variable outside of the function called requestRunning and on calling getProgress it checks if requestRunning is true.
// Pseudo-code
var requestRunning = false;
if requestRunning === true => continue with getProgress
if requestRunning === false => stop firing getProgress
Method #2:
Use setInterval and on success of the request and clear the interval.
var progressHandle = setInterval(function(){getProgress(id)}, 1000);
$.ajax({
success: function() {
clearInterval(progressHandle);
}
});
I'd probably prefer the first option although progress checking through subsequent AJAX calls isn't really good.
i have a jquery .click() function that executes an .ajax() method call
$(".btn-play").live("click", function () {
//set globalSortNumber
globalSortNumber = $(this).parents("[sortnumber]").attr("sortnumber");//.attr("value") ; //change should be some type of input like mediaid //see if its possible to add the sortID to the handle span
// alert(globalSortNumber);
//set title
//set mediaID
var mediaID = $(this).parents("[mediaid]").attr("mediaid");
// alert(mediaID);
//ajax query to get link and excute code to launch music
$.ajax({
type:"POST",
url:"ajax/AB3Ajax.asmx/GenerateLink",
data:"{'mediaId':" + mediaId + ",'userId':" + "0" + "}",
contentType:"application/json; charset=utf-8",
dataType:"json",
success:function (msg) {
if (msg.d != "") {
playsong(msg.d,null);
}
else {
soundManager.stopAll();
//look at what is already in place in mystudio
}
},
error: function (err) {
//add code later look at what is already in place in mystudio
}
})
when the .ajax() method executes succesfully it calls a javascript function
function playsong(sortNumber,url) {
if (soundManager.supported()) {
globalSortNumber = sortNumber;
var aSoundObject = soundManager.createSound({
id: 'mySound' + sortNumber,
url: url,//'/Music/mafiamusicpt2rickross.mp3',
whileplaying: function () {
if (count == 0) {
if (this.position > 1000) {
this.pause();
pos = this.position;
count++;
this.resume();
}
} else if (count == 1) {
soundManager._writeDebug('old position: ' + pos);
soundManager._writeDebug('new position: ' + this.position);
// See that this.position is less than pos!
count++;
}
},
onfinish: function () {
//find the next song in the list
//var nextSongPosition=
this.destruct();
$.ajax({
type:"POST",
url:"ajax/AB3Ajax.asmx/GenerateLink",
data:"{'mediaId':" + mediaId + ",'userId':" + "0" + "}",
contentType:"application/json; charset=utf-8",
dataType:"json",
success:function (msg) {
if (msg.d != "") {
playsong(msg.d,null);
}
else {
soundManager.stopAll();
//look at what is already in place in mystudio
}
},
error: function (err) {
//add code later look at what is already in place in mystudio
}
})
playsong(sortNumber++,url)
}
});
aSoundObject.play();
}
}
as you can see i have an .ajax() method inside my javascript function, is this possible?
I am creating loop that starts on the finish listener of the soundmanager object. So when I need to make the ajax call to get he next url I need. If my way isnt correct can you please tell me what is the best way to accomplish what i am trying to do.
Think it's fine but i would make a separate function for the ajax call so you dont need to duplicate the code twice. Easier to maintain.
$(".btn-play").live("click", function () {
//set globalSortNumber
globalSortNumber = $(this).parents("[sortnumber]").attr("sortnumber");//.attr("value"); //change should be some type of input like mediaid //see if its possible to add the sortID to the handle span
//alert(globalSortNumber);
//set title
//set mediaID
var mediaID = $(this).parents("[mediaid]").attr("mediaid");
//alert(mediaID);
//ajax query to get link and excute code to launch music
getAudio(mediaID);
}
function playsong(sortNumber,url) {
if (soundManager.supported()) {
globalSortNumber = sortNumber;
var aSoundObject = soundManager.createSound({
id: 'mySound' + sortNumber,
url: url,//'/Music/mafiamusicpt2rickross.mp3',
whileplaying: function () {
if (count == 0) {
if (this.position > 1000) {
this.pause();
pos = this.position;
count++;
this.resume();
}
} else if (count == 1) {
soundManager._writeDebug('old position: ' + pos);
soundManager._writeDebug('new position: ' + this.position);
// See that this.position is less than pos!
count++;
}
},
onfinish: function () {
//find the next song in the list
//var nextSongPosition=
this.destruct();
getAudio(mediaId);
playsong(sortNumber++,url)
}
});
aSoundObject.play();
}
}
function getAudio(mediaID) {
$.ajax({
type:"POST",
url:"ajax/AB3Ajax.asmx/GenerateLink",
data:"{'mediaId':" + mediaId + ",'userId':" + "0" + "}",
contentType:"application/json; charset=utf-8",
dataType:"json",
success:function (msg) {
if (msg.d != "") {
playsong(msg.d,null);
}
else {
soundManager.stopAll();
//look at what is already in place in mystudio
}
},
error: function (err) {
//add code later look at what is already in place in mystudio
}
});
}