I'm at a loss right now. I'm using a simple variable, whose value is assigned during a loop. After exiting the loop, the value of the variable is still undefined, unless I alert it's value first. Then everything works fine. What's going on here?
$(myarray).each(function(idx, item)
{
fetchSomethingRemotely( success: function(data) {
item.someValue = data; });
// if the following alert is not there, doSomething will never get called
// and the alert after the else will show item.someValue as undefined.
alert(item.someValue);
if (item.someValue != null) { doSomething(item.someValue); }
else { alert(item.someValue); }
});
Edit:
Okay, so I've got a better handle in this now. The value assignment (item.someValue=123) happens inside of a callback function within this iteration. So the value is probably not there yet when I serially try to access it a couple of code lines below. How could I wait for the value to be assigned?
How could I wait for the value to be assigned?
The answer is already in your code. Just move doSomething into the callback function.
fetchSomethingRemotely( { success: function(data) {
item.someValue = data;
if (item.someValue != null) doSomething(item.someValue);
} });
Note that this will still move on to the next item before the current item has got its value. If you must perform all of the iteration sequentially, you can do something like this:
function iterate(index) {
var item = myarray[index];
fetchSomethingRemotely( { success: function(data) {
item.someValue = data;
if (item.someValue != null) doSomething(item.someValue);
if (index < myarray.length - 1) iterate(index + 1);
} });
}
And then you would fire off the whole process with iterate(0).
Did you remember to use var to define the variable. Are you sure the variable exists in the scopes you are using it. If you do for ( var i ... then it will only exist in the for scope, not outside it. You can use Webkit (Chrome, Safari)'s Developer Tools to debug your script by setting a breakpoint on the problem line, and then in the right column you can see all variables defined in the related scopes.
"How could I wait for the value to be
assigned?"
Welcome to asyncronous programming!
You're going to need to put everything in the callback, not just the variable assignment.
Related
I've following Javascript code snippet :
authData=ref.getAuth();
if(authData == null){
//TODO find an elegant way to manage authorization
// window.location = "../index.html";
} else {
ref.child("users").child(authData.uid).on("value", function(snapshot){
$( "span.user-name").html(snapshot.val().displayName);
loggedInUser.displayName = snapshot.val().displayName;
//alert("Name inside : "+loggedInUser.displayName);
//Here it displays the value
});
}
alert("Nameada is out : "+loggedInUser.displayName);
//Here it shows 'undefined'
why?
I want to use the variable value loggedInUser.displayName where did I shown alert.
Can someone please help me in accessing the value and displaying the alert?
Thanks.
Your final alert is executed when the callback function (function(snapshot){ ... }) has not yet been called. Note that the callback function is called asynchronously, so it only gets executed after the currently running code has completed and the value event is triggered.
This also explains why the inner (commented out) alert does work. Just realise that this piece of code (the call back function) is executed later than the other alert, even though it occurs earlier in your code.
You could "solve" it by calling another function from within the call back, like this:
authData=ref.getAuth();
if(authData == null){
//TODO find an elegant way to manage authorization
// window.location = "../index.html";
} else {
ref.child("users").child(authData.uid).on("value", function(snapshot){
$( "span.user-name").html(snapshot.val().displayName);
loggedInUser.displayName = snapshot.val().displayName;
whenUserLogged();
});
}
function whenUserLogged() {
alert("Name : "+loggedInUser.displayName);
// anything else you want to do....
}
Some suggestions for improvement
Don't use too many global variables (in your code all of them are global), and instead pass variables as function arguments.
You may want to look into promises.
I'm trying to retrieve an entire object from a Parse database, but this is not a Parse-specific problem. I'm trying to use the object's unique ID to retrieve the whole object and assign it to the resultObject variable, so that I can save a reference to the resultObject later within this same addPerk function.
What's happening is that the alert() on the final line of the block below si coming back saying that resultObject is undefined. I believe this is because the objectQuery's success function is called after the alert() line, due to the asynchronous nature. However, I thought I could fix this by making a while() loop to make the program wait until resultObject is defined. Why doesn't this work? How else could I get the resultObject out of the scope of the success function?
I don't want to move all of my remaining logic into the success block of the query, I'm already experiencing major "pyramid of death" and don't want to make the code any more difficult to read.
addPerk: function()
{
var resultObject;
var Object = Parse.Object.extend("Object");
objectQuery = new Parse.Query(Object);
objectQuery.get(objectId, {
success: function(object) {
alert("returned object in success function is " + object);
resultObject = object;
alert("resultObject in success function is:" + resultObject);
},
error: function(object, error) {
alert("error: " + error.code + ", " + error.message);
}
});
while (typeof correctProvider == "undefined") {
setTimeout(null, 3000);
}
alert("resultObject (after WHILE loop) is: " + resultObject);
Why doesn't this work?
while (typeof correctProvider == "undefined") {
setTimeout(null, 3000);
}
This is your logic:
Enter the while loop
Set a timeout
Go to 1
JavaScript loops around and around the loop setting up as many timeout handlers as it can before running out of memory.
It is too busy looping to see if any of them have ever actually timed out, or to run the success function.
How else could I get the resultObject out of the scope of the success function?
You don't.
You have to go forwards from the callback, you can't go back.
Make the callback do the work you want to do when you get the data.
I'm having issues when adding an element validation within an if-statement.
Basically, irrelevant of the result of the if-statement, Protractor is still trying to find the element specified within the if-statement.
Here is the code that is still running even though the if-statement returned false:
if (thisIsAlwaysFalse == true) {
console.log(':::::::::::::::' + thisIsAlwaysFalse);
it('If-statement test', function(done) {
var elementToFind = element(by.xpath('//td[contains(#class,"hello")]'));
browser.wait(function() {
return browser.isElementPresent(elementToFind);
}, 5000);
elementToFind.click();
done();
});
}
Also, funny thing is that the console.log part is successfully ignored!
Anyone has a solution for this or possibly knows why this is happening?
Thanks in advance :)
Have you debugged the problematic area?
Nevertheless, your always-false statement is probably a promise, which is always a truthy value. In order to solve it, you need to put the whole block to then callback.
For example:
doStuff()
.then(function (result) {
if (yourAlwatsFalsyCondition(result) {
return elementFindYouDid(results)
.moreStuff(doMore);
}
})
I have the following function:
function loginStudent() {
var advisorKEY = "<dtml-var expr="py_get_alias()">";
var studentKEY = "<dtml-var SID>";
var URL = "py_logging_sessionOpen?AdvisorKEY=" + advisorKEY + "&StudentKEY=" + studentKEY;
key = "";
$j.get(URL, function(data) {
key = data;
});
alert(key);
}
The py_loggin_sessionOpen is just a python script running on my server.
It returns a single string. I need the response of that script to determine the next action. The script returns the value perfectly, and I can easily check the value by putting an alert within the function(data) in get.
My main question is: how to get the key value to be changed outside the scope of function(data)?
I assumed because I defined it externally it would act as a global variable.
Moving it outside loginStudent() does not solve the problem either.
Any ideas?
$j.get() is going to be an asynchronous call. That means it fires, and the rest of the execution continues. Anything that relies on that call needs to be done in the callback, like so:
$j.get(URL, function(data) {
key = data;
alert(key);
} );
If everything else is good, you'll see the value you expect.
The problem with your code is that $j.get executes asynchronously. That's the reason you pass a callback to it.
If you wish to write asynchronous code synchronously then you should read this answer: https://stackoverflow.com/a/14809354/783743
Edit: It seems that you have created a global variable called key by not declaring it with var. Hence it should be visible in other functions as long as they are called after the callback.
Would you care to provide us these other functions?
I am new to javascript, and can't find the solution to this.
I have read some of the similar questions, but did not look like the problem was the same as mine.
I call a method from script1 with this code:
function turnPage(){
var current = window.now;
var nextpage = getNextPage(current);
alert(nextpage);
}
In script2 there is a SQLite etc:
function getNextPage(Pid) {
db.transaction(function(tx) {
tx.executeSql('SELECT * FROM Page WHERE Pid=' + Pid, [],
function(tx, results) {
nextp = parseInt(results.rows.item(0).NextPage);
//alert(nextp);
return nextp;
}, errorCB);
}, errorCBQuery);
}
if I use the alert-dialog in the called function, the variable nextp is 2.
BUT if I return the variable, it will alert as 'undefined'.
Also, if I etc make the variable var nextp = 11; over "db.transaction..." and the return-statement at the end of the function, it will return 11 instead of 2.
Is it because the variable is not sent to the inner function in my inception of functions? :)
Any ideas of what to do? thanks!
I don't know how SQLite in javascript works, but I suspect it works asynchronously, so you're calling alert in turnPage but the transaction is running async and the return value is in another scope anyway. You can try passing a callback function to getNextPage and then instead of returning nextp call the callback with nextp as argument:
function turnPage(){
var current = window.now;
getNextPage(current, function (nextp) { alert(nextp); /* do whatever else you need to do */ });
}
function getNextPage(Pid, cb) {
db.transaction(function(tx) {
tx.executeSql('SELECT * FROM Page WHERE Pid=' + Pid, [],
function(tx, results) {
nextp = parseInt(results.rows.item(0).NextPage);
cb(nextp);
}, errorCB);
}, errorCBQuery);
}
Your outer function never actuallay returns nextp at any time.
There are two solutions to what (I think) you are going to do
Create a global variable and store the value of nextp there.
Introduce another callback to use the value of nextp, e.g., create a new link or whatever. If you want, you can put the code either in another function and pass it as a parameter to getNextPage() or put the code directly into the most inner function (at the position of your alertcall).
Note that callbacks are used to handle the asynchronous nature of many JavaScript APIs. So even your getNextPage() can't return the value of the inner query as that value is not present, when getNextPage() is finished.
Anyway the return statement in the most inner function can be dropped as there is no function to actually receive that value.
As it is now, there are several problems with your code.
As JavaScript mostly is asynchronus, your code:
nextpage = getNextPage(current);
alert(nextpage);
Will call getNextPage() but it will not wait for the response before moving on, so the alert will be fired right away, and at that point, if the response hasn't been returned and assigned (which is likely to be the case), then nextpage will be undefined.
Your second problem is that your outer function does not return anything. You return the value from your inner function, but then "it get stuck" in your outer function. One solution would be to assign the value to a global variable, instead of returning it from the function. You would still have to look out for the "asynchronous-problem", so that you don't read the global variable until it has been assigned.