javascript setTimeout function out of scope - javascript

I am trying to call showUpload(); from within two setTimeouts. Neither works. It seems to be out of scope and I'm not sure why. I tried this.showUpload() which didn't work either.
$(document).ready(function(){
var progress_key = $('#progress_key').val();
// this sets up the progress bar
$('#uploadform').submit(function() {
setTimeout("showUpload()",1500);
$("#progressbar").progressbar({ value:0}).fadeIn();
});
// uses ajax to poll the uploadprogress.php page with the id
// deserializes the json string, and computes the percentage (integer)
// update the jQuery progress bar
// sets a timer for the next poll in 750ms
function showUpload() {
$.get("/myid/videos/uploadprogress/" + progress_key, function(data) {
if (!data)
return;
var response;
eval ("response = " + data);
if (!response)
return;
var percentage = Math.floor(100 * parseInt(response['bytes_uploaded']) / parseInt(response['bytes_total']));
$("#progressbar").progressbar({ value:percentage})
});
setTimeout("showUpload()", 750);
}
});
Thank you for your time.

As #Daniel said, this should work:
setTimeout(showUpload, 750);
Please note that the quotes should be removed (this is why it isn't being executed until the timeout runs out). Right now, you are passing a string, which is evaled when the timeout runs out. This eval will happen in a different scope, which is why you are seeing the problem you are seeing.
Instead, passing a reference to the showUpload function to setTimeout will allow your function to be executed later. Keep in mind that when it runs, it will be in a different scope, so you may have other scope issues, like with progress_key. You will need to create a closure around showUpload to capture that parameter.

It looks like you need to remove the parenthesis from showUpload in both your setTimeout calls. Otherwise you will be invoking the showUpload method instead of passing it as a parameter:
setTimeout(showUpload, 750);

Related

Creating a sprite inside of setInterval

Using the setInterval function, I'm trying to create a sprite once every second on code.org using javascript, so my first version of the code looks like
setInterval( function() {
createSprite(200,200,20,20)
}, 1000)
My problem is that putting setInterval inside of the Draw function causes it to not work properly and a sprite is created every tick after one second has passed, and when the setInterval is not put into function Draw it does not draw the sprite like I want it too.
One solution I have tried is putting the Draw function inside of setInterval but it is not recognized and gives the error message "Draw is defined, but it is not called in your program".
Is there a different version of setInterval that works inside of Draw function, a way to put Draw inside of setInterval successfully, a way to make the sprite show up even though it is outside Draw, or a different way to solve this problem?
Specifically what I'm looking for is to create a sprite once every second, have it show up on screen, be able to choose different velocities for each sprite each time a new one is spawned, and being able to put this function inside of an if function and still have it work as intended.
a piece of code showing something that partially works is shown here:
https://studio.code.org/projects/gamelab/ApXezLpMzV3TfEfHx1CrhFyuteYDSKWe_6Hx0NdJgnc
It works in the regards that it spawns a sprite every second, but if I try to assign one of the sprites that got spawned a velocity, It only works for the first one, as shown here:
https://studio.code.org/projects/gamelab/ApXezLpMzV3TfEfHx1CrhFyuteYDSKWe_6Hx0NdJgnc
the only way I think a solution could be made would be by declaring a class, and then creating a sprite of this class inside the setInterval function, but I do not know exactly how to do this.
So i think that your problem is that the sprite generates only after a second, right?
If so, please try this:
createSprite(200,200,20,20);
setInterval( function(){ createSprite(200,200,20,20)},1000);
See comments:
// just a helper function to generate random velocities
function random_in_range(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min }
var monster = createSprite(200,200,20,20);
monster.velocityX = 5;
setInterval(function() {
// as you needed to set velocity for a newly created sprite
// you need to have this sprite as a variable
var fireball = createSprite(monster.x,monster.y,4,4);
// now you can set it's velocity
fireball.velocityX = random_in_range(1,6);
// basically that's it.
// as you don't do anything else with a "fireball"
// you can just forget about it, and you don't need to save it anywhere
}, 1000);
function draw() {
background("white");
createEdgeSprites();
monster.bounceOff(edges);
drawSprites();
}
The link with the working code
Looking at your original code and your question I think that you may have some basic misconseptions about JS (sorry if I misjudged). Explained them in the comments to your code. I also added some lines to illustrate my points:
var spawner = createSprite(200,200,20,20);
var remember_spawner = spawner // ADDED
// After a new sprite created it does't change 'spawner' variable
createSprite(150,200,15,15).velocityY = 3; // ADDED
console.log(remember_spawner === spawner) // ADDED // you see it's the same
// you need to assign the newly created sprite to a variable
// you can think of this as:
// I need give them different names so that they can understand to whom am I taking to
// and if you don't name them they won't listen to you at all
var spawner2 = createSprite(100,200,10,10); // ADDED
spawner2.velocityY = 1 // ADDED // now you cat change velocity of another sprite
console.log(spawner !== spawner2) // ADDED // and it is another sprite
// var thing_to_be_spawned = createSprite(spawner.x,spawner.y,4,4);
// You probably don't need this. And you don't use the variable anyway.
// This sprite created at the same time as the spawner.
// But if you need it, and you want it to move - change it's velocity (thing_to_be_spawned.velocityX = something) not the velocity of spawner
// And it would be better if you'll name the function passed to setInterval
// and call it instead of repeating it. Like so:
// function fire() { ... } // define the function
// fire() // call the function
// setInterval(fire, 1000) // call the function every second
setInterval(function(){
console.log("This function executed every second") // ADDED
console.log("Fire!") // ADDED
createSprite(spawner.x,spawner.y,4,4);
console.log("Done") // ADDED
},1000);
console.log("Next line executed only once") // ADDED
spawner.velocityX=5;
// The fact that it's placed after setInterval() does mean that
// it will be executed after call to setInterval()
// but it doesn't mean that it will be executed after the function passed to setInterval(). Let's call it fire(), shall we?
// Actually, the fire() function will be called only after all the code in this file
// And setInterval() is also called only once, only the fire() passed to it called every second
function draw() { // Here you don't call draw() you only define it, so that code.org can call it whenever it wants
// looking at the code draw function we can't tell when or how often it's called
// it depends on the implementation details of code.org.
// We can add console.log to find out
console.log("Draw called") // ADDED
background("white");
createEdgeSprites();
spawner.bounceOff(edges);
drawSprites();
}
console.log("'fire()' not called yet") // ADDED
Console logs can be seeing in Debug Console of studio.code.org. It opens with a click on Debug Commands. Use it! I mean console.log(). I could also say "use Debug Commands!" but debug is poorly implemented in studio.code.org and can be misleading... You should definitely give it a try, but your trust you should put in console.log().

How to use Ajax to populate externally loaded div (jQuery)

I am creating tests for a page and HAVE to use jQuery to change elements on the control version of the page for each different experience.
I'm using jquery to load an element from an external page and replace a div. However, on the external page, it uses an ajax call to an api to populate the div, so I copied over the function with the ajax call.
I think it is attempting to make the ajax call before the new div is actually loaded on the page.
I've tried moving the function, wrapping the load function within the ajax call, but it still doesnt work.
I could be missing something obvious, but here's that part of my code:
$('.replace-div').load('external.html #replace-div');
function waitForLoad() {
if ($('#replace-div')) {
var object;
$.ajax({
url: "https://api.com",
async: false,
success: function(result) {
object = result;
var variable1 = object["blah"][0].value,
var variable2 = object["blah"][0].value,
var variable3 = object["blah"][0].value,
var variable4 = object["blah"][0].value,
$('newElement').attr('href', variable1);
$('newElement2').attr('src', variable2);
$('newElement3').attr('href', variable3);
$('newElement4').text("text" + variable4 + "more text");
}
});
} else {
setTimeout(waitForLoad, 15);
}
}
waitForLoad();
I don't get any errors in the console, and when I paste the above waitForLoad function into the console, it populates totally fine. obviously this is after the page loads the new div, so i just need to know how to make the ajax call wait for the load.
I've tried .ajaxComplete(), but it doesnt help.
$(function() {}); also does not work
.load() has a callback argument where you supply a function to run after the data is loaded.
$('replace-div').load('external.html #replace-div', function() {
$.ajax(...);
});
So, what happens is that, once waitForLoad is called for the first time, it doesn't see the div loaded, the code goes to the else block and executes again with a 15ms timeout. 15ms is not enough for the div to load, most likely.
You can try three things (ordered from worse to better):
Try increasing the timeout to a bigger number. Start with 1000 (1000ms - 1 second) and see if it works or you need to increase it. It's more likely you'll have to decrease it
Try using setInterval instead of setTimeout, which will repeat itself. Of course, once it loads, you'll need to clear the interval so it stops. Also, better use bigger timeouts/intervals, like 50 or 100ms b/c the fast firing timers can slow down a page a lot
E.g.
$('.replace-div').load('external.html #replace-div');
function waitForLoad() {
if ($('#replace-div')) {
clearInterval(window.waiter);
...
} else {
window.timer = setInterval(waitForLoad, 50);
}
}
waitForLoad();
Same as 2, but using more idiomatic callback function after load call.
// the window.waiter is the interval handle, and it will run every 100ms. It calls .load every time, and if the #replace-div is found, unsets the interval handle.
window.waiter = setInterval(function() {
$(".replace-div").load("external.html #replace-div", function() {
if ($(".replace-div #replace-div").length) {
// found the DIV
// code...
clearInterval(window.waiter); // bye interval handle, thanks
}
});
}, 100);

Q.js - how to access a cached element

Ok, so I'm using Q.js to help with keeping users notified of a potentially long calculation going on asynchronously (using setTimeout with zero delay to repeatedly call a function a set number of times).
However, this does not work:
var status = d3.select('#status');
var t = transfer({
N: 100
});
t.then(function (values) {
status.text('');
column_chart(values);
}, function (error) {
status.text('There was an error calculating the transfer probabilities')
}, function (progress) {
status.text('Calculating ' + Math.round(progress) + '%');
});
For some reason the status element is undefined inside the resolve, reject and progress functions. However if I replace each status.text with d3.select('#status').text then it all works fine. I'm a bit confused as to why I can't used a cached element?
OK, there was a problem with the name of my cached element!
var status = d3.select('#status');
Changing its name fixed the problem
var statusEl = d3.select('#status');
It turns out inside my promise functions status was the raw HTML element which of course had no text method. This is that weird thing where all DOM elements with ID's are added to the global window object...

Wait for data to be added to a Div

Ok, I have a div:
<div class="moreStuff"> <p>stuff in here matters</p></div>
and some Javascript:
weiredFunction(takes,some,values);
this "weirdFunction()" takes some values, does some non-important stuff and adds/appends it to the div.moreStuff.
Directly after "WeirdFunction()" I have my own function:
stuffIWantToDo(...);
the "stuffIWantToDo()" checks the div.moreStuff and reacts according to the data in it.
the problem is that it takes about 300ms for the "weirdFunction()" to do it's buisness and add it's data to the div .moreStuff but my function "stuffIWantToDo()" exicutes before 300ms; meaning there is nothing in the div .moreStuff when "stuffIWantToDo()" runs.
I want to prevent "stuffIWantToDo()" from running untill "weirdFunction()" appends the data to the div.moreStuff.
try make stuffIWantToDo() as a callback function in weiredFunction()
function weiredFunction(callback) {
// finish the weird thing
// Call the callback
callback('some','stuff','there');
}
function stuffIWantToDo(a, b, c) {
// I'm the callback
alert(a + " " + b + " " + c);
}
weiredFunction(foo);
Check this SO post: Create a custom callback in JavaScript
If you are using some jQuery calls, then we need to see it, as #tymeJV already said, look's like you have some async code involve in weiredFunction function
If not, your code must work synchronously and the only thing you need, is call your stuffIWantToDo functionas a callback, or at the end of the first one.
If none of this make sense to you, then use the old and well know setTimeout javascript function
like
function weiredFunction(takes,some,values){
/* some weired stuff here */
setTimeout(function() {
stuffIWantToDo(...);
}, 300);
}
If i understand you right, you have no possibility to change the weiredFunction. Based on that assumption, you have to write a small interval-based observer that fires your function once the content has changed.
var stuffContent = '';
window.setInterval(function() {
var currentStuffContent = $('.moreStuff').html();
if(currentStuffContent == stuffContent) return;
stuffContent = currentStuffContent;
stuffIWantToDo();
}, 50);
However, it would be the best if you could simply fire stuffIWantToDo within weiredFunction as a callback.

How can I run some code on all the nodes in a tree?

I want to run some code on all my treeView nodes depending on a value returned from the database and repeat this until a certain value is returned.
I was thinking that:
Give all my tree nodes the same css class so I can access them from JQuery
have a timer in my JQuery function that used ajax to go to the database, when a certain value is returned then stop the timer
Two questions here. How can I make my function run for each of the nodes and how do I do a timer in JavaScript, so:
$(function(){
$('cssClassOfAllMyNodes').WhatFunctionToCallHere?((){
//How do I do Timer functionality in JavaScript?
ForEachTimeInterval
{
//use Ajax to go to database and retrieve a value
AjaxCallBackFunction(result)
{
if (result = 1)
//How to stop the timer here?
}
}
});
});
Hope i'm clear. Thanks a lot
thanks a lot for the answer. And i would like you to comment on the design.
Bascially what i'm trying to acheive is a Windows Wokflow type functionality where each node in my tree updates its image depending on its status, where its status is got from querying the database with a key unique to the tree node. I'm open to ideas on other ways to implement this if you have any. thanks again
Without commenting on your design you can refer to these
$.each()
setTimeout() or setInterval()
You can do:
$(function(){
$('cssClassOfAllMyNodes').each(function (){
// Do something with "this" - "this" refers to current node.
});
});
Te proper way to handle timers in JS is to have a reference to each timeout or interval and then clearing them out.
The difference between them is:
The timeout will only run once, unless stopped before;
The interval will run indefinitely, until stopped.
So you can do something like:
var delay = 2000; // miliseconds
var timer = setTimeout("functionToBeCalled", delay);
clearTimeout(timer); // whenever you need.
Please note you can pass a string to setTimeout (same with setInterval) with the name of the function to be called. Or you could pass a reference to the function itself:
var callback = function () { alert(1); };
var timer = setTimeout(callback, delay);
Be sure not to set an Interval for AJAX requests, because you response might be delayed and successive calls to the server could eventually overlap.
Instead, you should call setTimeout and when the answer arrives then call setTimeout again.

Categories

Resources