This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 6 years ago.
I have a basic function in JavaScript that simply takes some pre-set values and puts them onto the screen by the use of a pre-made function. When I breakpoint the first line of what it is I'm doing, the page loads fine, as expected, but as soon as I remove that breakpoint, none of the information is set. and the page is blank.
this.QuizSelection = function () {
// Fill the ID's with the right info
app.SetBackground('head', this.HeroImage);
console.log('1 ' + this.HeroImage);
app.LoadInnerHTML('breadcrumbs', 'Home / ' + this.Title);
app.LoadInnerHTML('quizSelectionTitle',this.Title);
console.log('2 ' + this.Title);
app.LoadInnerHTML('quizSelectionIntro',this.Introduction);
console.log('3 ' + this.Introduction);
// Show the Quiz Selection and Heading
app.ShowSection('head');
app.ShowSection('quizSelection');
console.log('Quiz Selection');
}.bind(this);
The functions inside that (SetBackground and LoadInnerHTML) are just small one line functions that change the inner html and the set a background image.
// Change Inner HTML
this.LoadInnerHTML = function (id, html) {
var d = document.getElementById(id);
d.innerHTML = html;
}
// Set Background Image
this.SetBackground = function (id, image) {
document.getElementById(id).style.backgroundImage = 'url(image)';
}
I can't understand why it wouldn't work when the breakpoint isn't on. Clearly it does work, because everything is fine with the breakpoint on, but then when it's off the result I get output to the console is:
1
2
3 undefined
Quiz Selection
You have a race condition.
The act of hitting a breakpoint makes your code wait for the async JSON load to complete. Without the breakpoint, the code trying to read the JSON is executing before the JSON has actually loaded.
See How do I return the response from an asynchronous call? for how to fix this issue.
You have console.log statements in your code. When the debugger is not on, console object does not exist (this is true for IE not for Chrome to the best of my knowledge), thus your javascript code execution fails.
Related
I have:
var newID = saveNewGame(newName, newShortName, "1");
alert (newID + " Here");
function saveNewGame(newName, newShortName, myNumber) {
myRequest.open("POST", "savegame.php", false);
if (myRequest.status === 200) {
var myNewID = myRequest.responseText;
alert(myNewID + " There");
return myNewID;
}
When ran, I get a popup message: 'undefined Here' followed by a popup message: '5 There'. - More complex code added. The function performs an XMLHttpRequest (myRequest) - but set to Async = false.
I'd think that '5 There' should popup first and 'undefined Here' should say '5 Here' and popup second. Why does this do what it does?
NOTE: I snipped out the XML setup stuff
When I run your code as you show it (with a definition for newName and newShortName in your answer in a jsFiddle here http://jsfiddle.net/jfriend00/a5da81kp/, it does not do what you said it does. In fact, it shows the two alerts with legitimate strings just like one would expect.
It shows:
5 There
5 Here
So, it seems likely that your real code is not as simple as the code you have in your question. I'd guess that you perhaps have some asynchronous code somewhere that does indeed change the order of execution. But the hypothesis in your question is simply not correct. That code works as one would expect.
I wrote a script that's running from ebay listing iframe. It's working fine, it runs on $(document).ready(), sends an AJAX request to a remote server, gets some info, manipulate the DOM on 'success' callback, everything working perfect...
However, I added a piece of code, which should get the document.referrer, and extract some keywords from it, if they exist. Specifically, if a user searches ebay for a product, and clicks on my product from the results, the function extracts the keywords he entered.
Now, the problem is, that function is not running on page load at all. It seems like it blocks the script when it comes to that part. This is the function:
function getKeywords(){
var index = window.parent.document.referrer.indexOf('_nkw');
if (index >= 0){
var currentIndex = index + 5;
var keywords = '';
while (window.parent.document.referrer[currentIndex] !== '&'){
keywords += window.parent.document.referrer[currentIndex++];
}
keywords = keywords.split('+');
return keywords;
}
}
And I tried calling two logs right after it:
console.log('referrer: ' + window.parent.document.referrer);
console.log(getKeywords());
None of them is working. It's like when it comes to that 'window.parent.document.referrer' part, it stops completely.
But, when I put this all in a console, and run it, it works perfectly. It logs the right referrer, and the right keywords.
Does anybody know what might be the issue here?
The reason it is working on the console is because your window object is the outer window reference and not your iframe. Besides that, on the console:
window.parent === window
// ==> true
So, on in fact you are running window.document.referrer and not your frame's window.parent.document.referrer.
If you want to access your frame's window object you should something like
var myFrame = document.getElementsByClassName('my-frame-class')[0];
myFrame.contentWindow === window
// ==> false
myFrame.contentWindow.parent.window === window
// ==> true
This might help you debug your problem, but I guess the browser is just preventing an inner iframe from accessing the parent's window object.
This question already has answers here:
chrome.storage.local.get and set [duplicate]
(3 answers)
Closed 8 years ago.
I have a chrome extension that is using storage and I can't get the value from the storage with one enter click.
There is a single input field. After the user enters a value and presses enter, the extension should take the value from storage and add the user's input to this value. The first enter press it doesn't work, but if user clicks Enter for second time, then stored value is seen.
I assume that problem is in the ordering of functions, but I can't understand where exactly.
Code in correct order:
var repo, moduleCodes, url;
// Third process
function getStoredUrl() {
chrome.storage.sync.get(function (item) {
url = item.savedUrl;
});
}
// Fourth process
function setVariables() {
repo = document.getElementById("repo").value.toLowerCase();
moduleCodes = {
admin: "EHEALTHADM"
};
}
// Second process
function openGraph() {
getStoredUrl();
setVariables();
if (moduleCodes[repo] !== undefined) {
// ERROR: field "test" doesn't have value url, but should to have
document.getElementById("test").value = url;
//window.open(url + moduleCodes[repo]);
} else {
returnError("Can't find repo " + repo, "repo");
}
}
var enter = 13;
// First process
function inputRepoListener(e) {
"use strict";
if (e.keyCode === enter) {
openGraph();
}
}
The whole code can be seen on gitHub repo: https://github.com/iriiiina/fisheyeGraph
This is a typical race condition, caused by asynchronous method calls.
The call to storage.sync.get is asynchronous, i.e. the normal program flow continues while the storage values are being retrieved. This means that also the assignment of the (still empty) url variable to the element with id test happens before the storage value retrieval has finished.
Solution: Move everything that should happen after the storage value has been retrieved into the callback of storage.sync.get. If, for example, you assign the url like that, it will work.
chrome.storage.sync.get(function (item) {
url = item.savedUrl;
document.getElementById("test").value = url;
});
So you need to restructure your code in order to meet this criteria.
For debugging, I want to be able to print messages, and have the line number prepended.
No, I don't want to get involved with a full-fledged debugger.
I have defined a global constant ln="thisline = new Error().lineNumber";
I have defined a
function println(msg) {
document.write("<br>at " + thisline + ":" + msg);
}
Then at the lines I want to debug I put a line saying:
eval(ln);
println("msg");
The problem is that thisline often doesn't get updated before the print, so I get long stretches with an unchanging line number. I never get more than 3 unique line numbers printed.
Is it just that the eval is too slow? Is there some way to wait till it finishes?
I tried a timeout:
const ln="setTimeout(function() {
thisline = new Error().lineNumber
}, 1000);"
but the global thisline never got set.
Or is it that there is some system limit on the number of errors I can raise?
If you are running the application in IE, then press F12 key(Developer tools) and another popup will open.
click on the Script Tab and click on Start Debugging button.
the page will refresh and you can start performing actions.
on any error, the debugger will automatically take you to the error line number. you can also place break points.
else you can look at the below following post:
How can I get a Javascript stack trace when I throw an exception?
For those who wants the soluce before the question :
1 ) Don't read an element with getElementById() before it's really created : see windows.onload.
2 ) If you are using XMLHTTPRequest and AJAX stuff, call you're getElementById() , or unlock this function, in the callback ,(xhr_object.readyState == 4 part of your request).
In my case, i call my page without using the desired callback (noobish Ctrl-C Ctrl-V style).
Here was the question :
I'm facing a strange case in a HTML/Javascript code.
The aim of this code is to get the value of an HTML input (type text) via a JS function.
The context is that a main HTML page loads my all my JS functions, and loads on demand HTML contents in sub divs via HTTPRequest.
The selected code is called after the divs has been loaded.
Here's the PHP generated Input field that i have to read:
<input id="listejf" type="text" value="6|7|">
Here's my JavaScript call :
listejf=document.getElementById('listejf').value;
alert(listejf);
This code doesn't work. Firebug sends me:
TypeError: document.getElementById("listejf") is null
The strange thing is that I can make it work if I call the getElementById through an alert like this:
alert(document.getElementById("listejf"));
listejf=document.getElementById('listejf').value;
alert(listejf);
The first alert displays null, but the second one "6|7|", as expected.
Now, 2 questions:
Why does alert make it work ?
How can I make it work without throwing alerts everywhere?
Re-edit, the code was gone :
That's is the main HTML page : main.html
<head>
<script type="application/javascript" src="./preload.js"></script>
</head>
<body>
Link
<div id="targetid"></div>
</body>
preload.js looks like that :
function CallPagen() {
envoieRequete('./PageN.php', 'targetid');
}
function mytestfunction() {
listejf = document.getElementById('listejf').value;
alert(listejf);
}
function envoieRequete(url, id) {
var xhr_object = null;
if (window.XMLHttpRequest) xhr_object = new XMLHttpRequest();
else if (window.ActiveXObject) xhr_object = new ActiveXObject("Microsoft.XMLHTTP");
xhr_object.open("GET", url, true);
xhr_object.onreadystatechange = function () {
if (xhr_object.readyState == 4) {
if (!document.getElementById(id)) {
alert("id pas trouvé " + id);
}
document.getElementById(id).innerHTML = xhr_object.responseText;
mytestfunction();
}
};
xhr_object.send(null);
}
PageN.php just echoes the inputtext field with the value filled.
"...I can make it work if i call the getelement through an alert like this..."
This almost always means that you're making an asynchronous AJAX request.
"Why does alert make it work ?"
What happens is that the alert delays the processing of the next line of code long enough for the response to return.
Without the alert, the next line of code runs immediately, and the element is not yet available.
"How can I make it work without throwing alerts everywhere?"
This is a very common issue. The solution is that you need to put any code that relies on the response of the XMLHttpRequest request inside a callback to the request.
So if you're making a request through the native API, you'd add a onreadystatechange callback...
xhrRequest.onreadystatechange = function() {
if (xhrRequest.readyState === 4) {
// append the response text to the DOM
listejf=document.getElementById('listejf').value;
alert(listejf);
}
}
You should run the code after DOM is ready, when the alert() is called, document is loading and browser has time for creating the DOM objects, try the following:
The load event fires at the end of the document loading process. At this point, all of the objects in the document are in the DOM, and all the images and sub-frames have finished loading.
window.onload = function() {
var listejf = document.getElementById('listejf').value;
alert(listejf);
};