Looking trough this site I have seen a number of suggestions about how to update a global variable inside document ready, and then use it outside document ready. I have tried a number of combinations of these and none of these seem to work. Any help? What am I missing?
test = 0 ;
or
var test = 0;
or
test;
or
var test;
or no declaration outside document ready at all
then
$(document).ready(function(){
test = 4;
});
then later...
alert(test);
output:0, or undefined. Why oh why don't you output 4 like I want you to! I know, I wish I could just use a normal function where this works easily, but I can't. I need to use document ready to get some json/jplot material to work.
test = 4; will create a global variable and set it to 4. It's equivalent to the more explicit window.test = 4.
Before the global variable has been created it's value will be returned as undefined.
You need to make sure to call alert(test) after the document ready handler has run. That means you either need to call it in an event handler or call a function from inside document ready.
If you just call alert(test) below the document ready handler it will be executed immediately when the page is loaded - at that point its value will be undefined. Only once the document is ready the test is set to 4.
Also note that any local variables called test will shadow the global variable, i.e., the value of the local variable will be used instead of that of the global one. You can avoid this by using window.test.
There are two things you can do:
Add an id to the fields in the table and then set their content in the document ready handler
Insert the table once the rest of the page has finished loading and test has been set
I'd recommend the first approach:
$(document).ready(function(){
test = 4;
document.getElementById("test-value").innerHTML = test
});
With this html code:
<table>
<!-- ...whatever else you have -->
<td id="test-value"></td>
<!-- ... -->
</table>
If you want to use <script>document.write(test)</script> you need to insert the html code of the table by setting innerHTML (see above) to "..." inside the document ready handler.
You can do it like this but it will be more painful than this needs to be. If you just set innerHTML to something like "document.write(test)" the browser will think the script tag containing the document ready handler has been closed.
Instead I would suggest you use a template engine, such as _.template in underscore.js. Then you basically put the HTML inside a script tag and only show it when you're in document.ready. At that point you will be able to specify variables that will be replaced inside the template.
Related
I have a control on a javascript page. I can access this by id, but what I want to do is cache the control since I'm referencing it in a few places. How can I cache this control with say an id=TestControl
You can create a variable1 and safe a reference to the element (control) in it:
var testControl = document.getElementById("TestControl");
Ensure ou run that code after the element has been created (for instance, put the script tag at the end of the document, just before the closing </body> tag).
If you do that at the top level of your code, for instance:
// Scoping function to avoid creating globals
(function() {
var testControl = document.getElementById("TestControl");
// Your code here
})();
...all of your code will have access to the variable.
1 In fact, the browser has already done that for you by creating an automatic global called TestControl, but I never advocate using automatic globals. The global namespace is just too crowded, too easy to get bitten by conflicts.
The problem was that code needed to go in a $(document).ready() function. I was trying to reference it before the document loaded. Thank you for your very fast response!
I'm fetching an HTML document from the server, storing it in a variable data, then appending it to a <ul> element on the page. Here is what data looks like:
<script>
hasNext = true // global variable
</script>
<li class="result">one</li>
<li class="result">two</li>
Then in my main Javascript for the page, I do this:
ulElement.append(data);
if (hasNext) {
ulElement.append(nextPageButton);
}
It seems to work, but I just wanted to make sure that the code in the <script> tag will always run before my if statement. And I couldn't find any info on this possible race condition online. Thoughts?
Independent of whether or not this is a good idea....
In order for the browser to interpret your dynamically inserted DOM, it has to parse the content you are providing. This is a synchronous process (assuming your JS doesn't do any AJAX requests, setTimeouts etc). From the Google Dev blog:
When the HTML parser encounters a script tag, it pauses its process of
constructing the DOM and yields control over to the JavaScript engine;
once the JavaScript engine has finished running, the browser then
picks up from where it left off and resumes the DOM construction.
This means that the browser is guaranteed to process and execute the JS in the script tag (as well as add the DOM in the string) before it moves onto the next JS command: if (hasNext) {....
In your example it wouldn't matter where the <script> tag was in relation to the rest of the dynamically inserted DOM in data because there is no dependency between the DOM and that script. As long as it is in data, the browser will process those commands before proceeding to the line after append. E.g. this would work just as well
<li class="result">one</li>
<li class="result">two</li>
<script>
hasNext = true // global variable
</script>
Since your code is checking the dynamically 'injected' variable after the append call, the variable (hasNext) is guaranteed to exist (as long as it was in a <script> tag in data).
For example:
$( ".test" ).append( "<p>Test</p><script>var globalVariable = 123;" );
$( ".test" ).append( globalVariable );
will write:
<p>Test</p>123
The most likely race condition is from some server interaction not specifying the hasNext variable, in which case the code will either use the falsey value of that variable:
if (undefined) {
alert('I won\'t be called');
} else {
alert('I will be called');
}
-OR, the more risky version-
your if (hasNext) { ... } will use the previous value of that variable from a prior call to append with different data. This is quite risky and possibly the best reason for avoiding this approach.
If you really want to do it this way, maybe you can wait for the page to have loaded by using window.onload.
ulElement.append(data);
$(function(){
if (hasNext) {
ulElement.append(nextPageButton);
}
});
I'm currently making a website, and I'm creating a "manager" object onload in the body:
body id="real-world" onload="createARSim('ar-world','real-world','phone');">
createARSim(...) returns an object with a bunch of things in it that are useful. One such thing is a
var pageIndex
which monitors the current page.
I want to display the page number somewhere in the web page. Currently I am putting the code inline, like this:
<script> onload.pageIndex.toString(); </script>
the issue is that it throws this error:
TypeError: onload.pageIndex is undefined
And I'm not sure what to do about it. The js code in the constructor runs fine, but I can't find any way to access the returned object once I've finished running the constructor.
EDIT:
ok, I think I might know why it's not working. First, I need to use Document.onload to call the onload object that I've returned. However the bigger issue is how onload works -- I can't call an element of onload inline, because the constructor isn't actually executed yet when I run the inline javascript code (it calls after everything has loaded...).
So I can't just put it inline. I'll have to do some clever editing from the javascript to the div I'm putting it in directly, I think.
You can do the following to solve this problem
window.onload = function() {
var pageIndex = createARSim('ar-world','real-world','phone').pageIndex;
var textNode = document.createElement('text');
textNode.textContent = pageIndex;
document.body.appendChild(textNode);
}
This appends pageIndex to body.
I am currently coding in this way:
<script type="text/javascript">
var linkObj;
Is this a safe way to store data? My concern is what if a jQuery or other plug-in was to also use the variable linkObj. Also if I declare my variable like this then can it also be seen by other functions in scripts located in other js files that I include?
$(document).ready(function(){
var linkObj;
});
as long as you use the var keyword, any variable defined in that scope won't be accessible by other plugins.
I you declare a variable this way it will be accessible to all scripts running on the page.
If you just want to use it locally, wrap it in a function:
(function() {var linkObj; ... })()
However, this way nothing outside of the function will be able to access it.
If you want to explicitly share certain variables between different scripts, you could also use an object as a namespace:
var myProject = {}
myProject.linkObj = ...
This will minimize how many global names you have to rely on.
Wrap it in a closure:
<script type="text/javascript">
(function() {
var linkObj;
// Rest of your code
})();
</script>
This way no script outside your own will have access to linkObj.
Is this a safe way to store data?
This is not storing data per se, it's only declaring a variable in a script block in what I assume is an HTML page. When you reload the page in the future, it will not hold previous values.
My concern is what if a jQuery or other plug-in was to also use the variable linkObj.
That's a valid concern, like others have pointed out. However, you would expect plugins not to rely on scope outside the plug-in. This shouldn't impact a lot as good plug-in design would likely prevent this from happening.
Also if I declare my variable like this then can it also be seen by other functions in scripts located in other js files that I include?
Yes. As long as their execution is triggered after your script block gets loaded. This normally follows the order in which your script declaration appears in the page. Or regardless of the order they appear on the page if they are executed, for example, after the jQuery DOM 'ready' event.
It's common to hear that is good to avoid 'global namespace pollution', which relates to this concern. To accomplish that you can use a function to contain code, and directly invoke that function in your script block.
(function () {
var a = 1; // the scope is within the function
alert('The variable a is equal to: ' + a);
}) (); // the parenthesis invoke the function immediately
The following scenario is a problem I am having. I came to the conclusion that jQuery must not be ready when Javascript is executing by observing this scenario.
Scenario:
I have a Java application which injects Javascript script tags into the currently loaded DOM page. The following Java code runs inline Javascript which inserts jquery.js and myCode.js. myCode.js holds my Javascript codes.
browser.executeJavaScript("var head= document.getElementsByTagName('head')[0];" +
"var script= document.createElement('script');script.type= 'text/javascript';script.src= 'jquery.js';head.appendChild(script);" +
"var script4= document.createElement('script');script4.type= 'text/javascript';script4.src= 'http://myCode.js';head.appendChild(script4);");
In this Java application, I also have a buttonListener that fires a function in myCode.js in ActionPerformed();
executedJS = browser.executeJavaScript("replaceAllLinks()");
The problem that is encountered is nullPointerException at the above line when button is clicked. Accomodating for null case results in endless loop without any changes.
while(executedJS == null) browser.executeJavaScript("replaceAllLinks()");
The cause of the problem was pinpointed down to when jQuery functions, methods are present inside replaceAllLinks(); javascript function. when jQuery, methods were absent, no problems could be observed. There was not one instance of nullPointerException raised.
The only possible underlying issue would be that somehow jQuery library is not fully loaded while replaceAllLinks(); is being executed. If jQuery methods and functions were not in use, it doesn't matter and everything runs okay.
My question is then, how can I make sure that jQuery is fully loaded and available for use?
Every script relying on jQuery should be contained inside a DOM ready function. Such a function normally takes this form:
$(document).ready(function() {
/* code here */
});
and a shortcut to achieve the same thing would be:
$(function() {
/* code here */
});
Here's the documentation for further information on the ready method:
http://api.jquery.com/ready/
Declare some global variable at the end jquery.js, e.g.
window.jQueryIsLoaded=true;
and check this variable before using jQuery.
<edit>Forget this, see Salman A's comment below, should be the right answer.</edit>