Has anyone found that their javascript doesnt work, but when they step through the code it works fine ?
var cookie = getCookie('lusr');
var username = cookie;
if(!cookie){
$("#UserNav").load("loginform.html");
$("#loginbtn").click( function(){
var username = $("#usernametxt").val();
var password = $("#passwordtxt").val();
login(username,password);
});
}else{
$("#UserNav").load("user.htm");
$("#WelcomeUser").text("Welcome "+ username);
}
My issue occurs on this line :
$("#WelcomeUser").text("Welcome "+ username);
That's because load() is asynchronous: it returns right away, performs its work in the background, then calls a user-provided function when its task is complete. The stepping delay gives you the illusion that the function is synchronous and performs all its work before returning.
Therefore, you should pass a callback function to load() and perform your subsequent work inside that callback:
var cookie = getCookie("lusr");
if(!cookie) {
$("#UserNav").load("loginform.html", function() {
$("#loginbtn").click(function() {
var username = $("#usernametxt").val();
var password = $("#passwordtxt").val();
login(username, password);
});
});
} else {
$("#UserNav").load("user.htm", function() {
$("#WelcomeUser").text("Welcome " + cookie);
});
}
You are using the load() function which asynchronously fetches from the server. This means your form has not loaded by the time you go searching for its fields.
The reason it works when you step through is because it gives it time to load the form while you step.
You can use another version of load which has an asynchonous callback function, allowing you to provide functionality only to be called once the load is complete.
Check the jQuery docs for more info.
Related
My Google Scripts function keeps running even after returning the next function.
To summarise, I have a function (nightTargetSelection ) that calls another function (dayStart). And as soon as the second function gets called, I want the first one to stop running.
I have stripped down the function and removed everything that should not be relevant for this post. But please let me know if you need more information.
Firstly, I call a user-input form via the following code in GS:
function roleWakeUp (roleName, j){
var roleStrAppend = "<div id='id_role_name' style='display:none;'>" + roleName + "</div>";
var jAppend = "<div id='id_j' style='display:none;'>" + j + "</div>";
var actionInputDlg = HtmlService.createHtmlOutputFromFile('night')
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setWidth(600)
.setHeight(425);
var wakeUpText = roleName + " wakes up."
actionInputDlg.append(roleStrAppend).append(jAppend);
SpreadsheetApp.getUi().showModalDialog(actionInputDlg, wakeUpText);
}
Then I have the form submitted by a user via HTML/JS:
<script>
selected = select.options[select.selectedIndex].value
google.script.run.withSuccessHandler(selected).nightTargetSelection(selected);
google.script.host.close();
</script>
Back in GS, I have the nightTargetSelection (the problematic function that I need helped getting fixed)
function nightTargetSelection (selected){
return dayStart();
}
Finally I have the dayStart function that is called within nightTargetSelection.
function dayStart() {
Browser.msgBox("DAY START");
//If I do not close the msgBox within 6 minutes (GS timeout period), then nightTargetSelection times out.
roleWakeUp (roleName, j);
}
I am expecting that the nightTargetSelection function stops running as soon as dayStart is called.
Unfortunately that is not happening and the nightTargetSelection function only completes when the next nightTargetSelection gets called.
As you can see, dayStart function calls roleWakeUp , making it a loop between functions. I have omitted including the loop details into this question because I dont believe it is relevant. Let me know if it is relevant and I will provide more details.
I don't know if this is your problem but in this:
<script>
var selected=select.options[select.selectedIndex].value;
google.script.run
.withSuccessHandler(selected)//select is supposed to be a function name
.nightTargetSelection(selected);
google.script.host.close();
</script>
.withSuccessHandler(functionname or anonymous function)
Yes, because nightTargetSelection() will not terminate until all of the processes it called have finished or it times out.
Looks like the end of the cycle is Browser.msgBox("DAY START");. So allow your server code to finish execution and then use .withSuccessHandler() to call roleWakeUp() via the client-side script.
(I don't really know what your code is doing. nightTargetSelection() seems to be unnecessary given the information you provided. So the example below is an abstraction to show you the flow.)
Client-Side Script
<script>
function yourOriginal() {
selected = select.options[select.selectedIndex].value;
google.script.run
.withSuccessHandler(restartCycle) // Calls restartCycle() after nightTargetSelection() finishes
.nightTargetSelection(selected);
google.script.host.close();
}
function restartCycle(values) {
google.script.run.roleWakeUp(values.roleName, values.j);
}
</script>
Server-Side Scripts
function roleWakeUp(roleName, j) {
// opens the dialog
}
function nightTargetSelection(selected) {
return dayStart();
}
function dayStart() {
Browser.msgBox("DAY START");
return {"roleName": roleName, "j": j}; // Pass these values to client-side script
}
I have the following code I'm trying to make a simple hit counter with. However, it doesn't work when I run it locally. When I start newHits as blank, it throws the error: Uncaught Error: Reference.set failed: First argument contains undefined in property 'hits.number'.
When I start it at 1, it just doesn't change the value of the hits in the database. Any help is appreciated: I'm new to programming. Thanks so much!
$(document).ready(function(){
var database = firebase.database();
var hits;
var newHits = 1;
var hitsRef = firebase.database().ref('hits');
hitsRef.once('value', function(snapshot){
console.log("hitsRef.once called");
hits = snapshot.val().number;
console.log("hits: "+hits);
newHits = hits+1;
console.log(newHits);
});
hitsRef.set({
number: newHits
});
});
the simple way to do that by using transaction see here
$(document).ready(function(){
var database = firebase.database();
var hitsRef = firebase.database().ref('hits/number');
hitsRef.transaction(function(hits){
console.log("hitsRef.once called");
hits++;
return hits
});
}
This is due to async nature of once(). According to your code, both once() and set() are called for the same value of i at once.
If you want to test it, place your set() within a setTimeout() like,
setTimeout(function(){
hitsRef.set({
number: newHits
});
}, 2000);
You will see that your problem is solved but this is not the correct way.Try this instead,
var i = 1;
hitsRef.once('value', function(snapshot){
console.log("hitsRef.once called");
hits = snapshot.val().number;
console.log("hits: "+hits);
newHits = hits+1;
console.log(newHits);
})
.then( function() { // change starts here
hitsRef.set({
number: newHits
});
});
Your set() method will only be called when once() is done retrieving hits. This works because once() returns a promise and it is thenable.
Read these then() in javascript and promises.
I am just getting started with coding for FirefoxOS and am trying to get a list of files in a directory.
The idea is to find the name of each file and add it to the array (which works), but I want to return the populated array and this is where I come unstuck. It seems that the array gets populated during the function (as I can get it to spit out file names from it) but when I want to return it to another function it appears to be empty?
Here is the function in question:
function getImageFromDevice (){
var imageHolder = new Array();
var pics = navigator.getDeviceStorage('pictures');
// Let's browse all the images available
var cursor = pics.enumerate();
var imageList = new Array();
var count = 0;
cursor.onsuccess = function () {
var file = this.result;
console.log("File found: " + file.name);
count = count +1;
// Once we found a file we check if there are other results
if (!this.done) {
imageHolder[count] = file.name;
// Then we move to the next result, which call the cursor
// success with the next file as result.
this.continue();
}
console.log("file in array: "+ imageHolder[count]);
// this shows the filename
}
cursor.onerror = function () {
console.warn("No file found: " + this.error);
}
return imageHolder;
}
Thanks for your help!
Enumerating over pictures is an asynchronous call. Essentially what is happening in your code is this:
You are initiating an empty array
You are are telling firefox os to look for pictures on the device
Then in cursor.onsuccess you are telling firefox os to append to the array you have created WHEN it gets back the file. The important thing here is that this does not happen right away, it happens at some point in the future.
Then you are returning the empty array you have created. It's empty because the onsuccess function hasn't actually happened.
After some point in time the onsuccess function will be called. One way to wait until the array is full populated would be to add in a check after:
if (!this.done) {
imageHolder[count] = file.name;
this.continue();
}
else {
//do something with the fully populated array
}
But then of course your code has to go inside the getImageFromDevice function. You can also pass a callback function into the getImageFromDevice function.
See Getting a better understanding of callback functions in JavaScript
The problem is with the aSynchronous nature of the calls you are using.
You are returning (and probably using) the value of imageHolder when it's still empty - as calls to the "onsuccess" function are deferred calls, they happen later in time, whereas your function returns immediately, with the (yet empty) imageHolder value.
You should be doing in this case something along those lines:
function getImageFromDevice (callback){
...
cursor.onsuccess = function () {
...
if (!this.done) {
// next picture
imageHolder[count] = file.name;
this.continue();
} else {
// no more pictures, return with the results
console.log("operation finished:");
callback(imageHolder);
}
}
}
Or use Promises in your code to accomplish the same.
Use the above by e.g.:
getImageFromDevice(function(result) {
console.log(result.length+" pictures found!");
});
I have a page where the user can click a button to retrieve data via an xhr get request. While the data is loading and being parsed, I want a loading message to be displayed, which will be replaced with the data once it is ready. I'm using dojo libraries, so would rather not include jQuery or other libraries.
This is a simplified version of the set up I'm using:
HTML
<div id = "clickMe"> Click Me! </div>
<div id = "results" class = "hidden">
Please wait while we retrieve the results
</div>
CSS
.hidden {display: none;}
Javascript
// Bind function to click me div
var clickMe = document.getElementById('clickMe');
clickMe.addEventListener('click', getResults, false);
function getResults () {
// Display the loading message while results are retrieved
var resultsDiv = document.getElementById('results');
resultsDiv.classList.remove('hidden');
// Get the data and parse it here using a standard dojo.xhrGet method
var displayResults = getData();
// Output data to resultsDiv, overwriting loading message
resultsDiv.innerHTML = displayResults;
}
The problem I'm having is that the getResults function always waits until the getData function has completed before removing the 'hidden' class and showing the results div. This means that the user never sees the loading message, only the retrieved data, even if there's a delay while the data is processed. However, if I put an alert in the middle the function is forced to pause, the loading message is displayed:
function getResults () {
// Display the loading message while results are retrieved
var resultsDiv = document.getElementById('results');
resultsDiv.classList.remove('hidden');
// The loading message will be displayed if this alert is included
alert ("Hello world!");
// Get the data and parse it here using a standard dojo.xhrGet method
var displayResults = getData();
// Output data to resultsDiv, overwriting loading message
resultsDiv.innerHTML = displayResults;
}
I have tried replacing the alert with console.log, but it reverts to not showing the loading message. I've also tried setting up getting the data as a callback function inside displaying the loading message, but again it doesn't show anything. I have also tried with the get request set to sync: true as well as sync: false, but again no luck.
How can I make sure the loading message is displayed while waiting for getData?
Edit:
This is the getData function. I have tried both with and without syncing.
function getData() {
var targetUrl = //some url;
var restResponse;
dojo.xhrGet({
url: targetUrl,
sync: true; // no difference when this is omitted
load: function(result) {
restResponse = result;
}
});
// Parse the rest response - fairly long function so I won't paste it here
var parsedResponse = parseResult(restResponse);
return parsedResponse;
}
My recommendation is to learn how to write asynchronous code and dojo/Deferred.
Instead of getData, rename the method to loadData and
loadData: function() {
return xhr('', {...}); // this returns a deferred
}
function getResults () {
var resultsDiv = dom.byId('results');
domClass.remove(resultsDiv, 'hidden');
loadData().then(function(displayResults) {
resultsDiv.innerHTML = displayResults;
});
}
http://dojotoolkit.org/reference-guide/1.9/dojo/Deferred.html
You can use deffereds and promises in jQuery
http://www.bitstorm.org/weblog/2012-1/Deferred_and_promise_in_jQuery.html. If you work with ajax request you can chain like this (since jQuery 1.8).
var promise1 = $.ajax("/myServerScript1");
function getStuff() {
return $.ajax("/myServerScript2");
}
promise1.then(getStuff).then(function(myServerScript2Data){
// Both promises are resolved
});
I have a page which clients sometimes leave open for extended periods of time without refreshing (over 24hrs). Some of the actions on that page require valid PHP session so I have built a simple set of functions to run this check every 10 minutes.
2 Functions:
checkLogin()
refreshTimer()
We call checkLogin() to start, checkLogin() calls refreshTimer(). After timer completes it should call checkLogin(), which should call refreshTimer() and start the process all over again.
The first time we call checkLogin() directly things works great. However, when refreshTimer() tries to call checkLogin() I get a "function not defined" error for checkLogin().
From my research it looks like I should be able to call the checkLogin() without passing it to the refreshTimer().
I'm sure I'm probably missing something obvious. Thanks for your help!
function checkLogin()
{
$.ajax({
url: "/mysite.com/dev/includes/check_login_helper.php",
success: function(logged_in)
{
if(logged_in == "false")
{
// they are logged out - redirect them to login page
alert("logged out");
}
}
});
refreshTimer();
}
function refreshTimer()
{
var t = setTimeout("checkLogin()",15000); // do each 10 min currently shorter for test
}
//start the process up
checkLogin();
Fixed & using checkInterval
function checkLogin()
{
$.ajax({
url: "/mysite.com/dev/includes/check_login_helper.php",
success: function(logged_in)
{
if(logged_in == "false")
{
// they are logged out - redirect them to login page
alert("logged out");
}
}
});
}
setInterval(checkLogin(),15000); // do each 10 min currently shorter for test
Don't pass a string to setTimeout; it'seval in disguise. There is also no reason to capture the value returned by setTimeout in this case.
function refreshTimer()
{
setTimeout(checkLogin, 15000);
}
var t = setTimeout("checkLogin()",15000);
needs to be
var t = setTimeout(checkLogin,15000);
this method accepts functions and not strings.