This is probably a very simple issue, but I've been trying to use Firebase in an external javascript file that is being used with an HTML file and can't get it to work properly. I am planning to use this file for many other similar pages, so I'd rather keep it in an external document. Specifically, my code is:
$(function() {
var head= document.getElementsByTagName('head')[0];
var script= document.createElement('script');
script.src= 'https://cdn.firebase.com/v0/firebase.js';
head.appendChild(script);
var Database = new Firebase('https://myfirebase.firebaseIO.com/');
...
but when I try to run it, it says that the Firebase object/keyword is undefined. I know that the script is being correctly appended to the HTML page because I've checked the HTML on the page after running the code.
I have also read somewhere that you might need to have a personal server to run Firebase, but frankly I don't really know what that means - in any case, I use Mac OSX and run all of my HTML and Javascript in Chrome.
Thank you very much!
The problem is that using document.createElement does not force the script to be loaded and rendered before your inclusive script is invoked (it's being invoked now). There are no guarantees by this method on when the script you include will get invoked.
Additionally, you are loading the script onDomReady by putting it inside $(function() {...}); you would want to insert it into the header immediately, not wait for the entire document to load.
The simplest answer is to just put Firebase into the head of the html page; you haven't really explained your limitations here, but I assume this isn't an option for you. If it is, KISS.
Another simple answer is to utilize jQuery, since you obviously have it available.
$.getScript('https://cdn.firebase.com/v0/firebase.js', function() {
// now I can use Firebase
});
You can also accomplish this with other methods (wait until Firebase is defined using a setInterval; utilize other script retrieval methods besides document.createElement--try googling "load scripts dynamically via javascript load order"), but I think this covers your needs sufficiently.
Related
I have a platform that I am using at the moment that uses js, css and php files.
What I would like to be able to achieve is to force the device to reload just specific Javascript files.
If I make a change to a js file on the server I don't wish to reboot the device just to load the javascript change.
for example if in a function in one of these pages I have an alert('1'); and I wish to change this to alert('2'); I don't want to have to reload the whole device
I have tried a few javascript update scripts that add the file into the head element with a tag of the current timestamp. this doesnt seem to work, I think it downloads the file yet still continues to us the old one.
I am sorry if this is really vague. Please ask any questions and I will try and answer them
You can make a function that 'phones home' every time and gets what it needs to do.
For your example, you can make a function that makes an XmlHttpRequest, and your server would give it a value of '1' or '2'.
To expand, you can also make your server return a block of javascript code, and eval it, but bear in mind that generally using eval is a bad idea (see Why is using the JavaScript eval function a bad idea?)
How about this, at the moment you need to choose a js file to execute, you request the code by XMLHttpRequest. The code will be returned as string. Then use eval(code) to execute it.
For example, eval("alert('2')");
But, eval is evil..
Try this - worked for me. But remember to put this code as last part of body in you html.
<script type="text/javascript" language="javascript">
var versionUpdate = (new Date()).getTime();
var myscript = document.createElement("SCRIPT");
myscript.type = "text/javascript";
myscript.src = "scripname.js?v=" + versionUpdate;
document.body.appendChild(myscript);
</script>
The idea is after the ready() function completes, lets say user clicks a button. Then the java script code behind it will run ajax to retrieve some java script code snippets (as text), then it executes the code just downloaded.
Is it possible? Any frameworks can do it?
You don't even need ajax to do it. You can simply create a new script element with the src attribute set to your JS file and insert it in the DOM (usually in the head element).
var script = document.createElement('script');
script.setAttribute('src', 'myfile.js');
document.head.appendChild(script);
Thanks Tibos for providing me the clues. I used your code to search for what I want, and here it is.
Jan Wolter described his solutions to dynamically load and execute the javascript at run time.
(http://unixpapa.com/js/dyna.html). It seems that the unstable-ness of dynamic JS loading is related to the JS code file size. If JS code file is big, different browsers may behave differently. Jan provided a way to avoid it.
Thanks again.
I have included 3 external js files at the end of body.
Suppose my document already contains a js named as insertlibs.js and here is the code
var script1 = document.createElement('script');
script1.src='http://code.jquery.com/jquery-latest.js';
script1.type='text/javascript';
document.getElementsByTagName('Body').item(0).appendChild(script1);
// Similar way to include underscore
var script2 = document.createElement('script');
script2.src='hhttp://documentcloud.github.com/backbone/backbone-min.js';
script2.type='text/javascript';
document.getElementsByTagName('Body').item(0).appendChild(script2);
But what is happening sometimes, it is throwing an error that $ is not defined and I tried to debug in Firefox and there is a parallel download occurring for jquery and backbone and sometimes backbone library getting download earlier than jQuery which is causing this error.
As far as i know that if a script tag is included, it will block further request So as soon as I add jquery in dom. I am confused about the workflow here happening.
So i have found the solution, I merged both the js and making a single call which is working perfectly but that does not explain me the flow happening in above case. Please help.
This is because you are attempting to include backbone without ensuring that jquery has been completely loaded. To correct this, you can use the script's onload attribute to attach a callback which will be fired when jquery is loaded.
For ex:
var script1 = document.createElement('script');
script1.src='http://code.jquery.com/jquery-latest.js';
script1.type='text/javascript';
// add an onload handler
script1.onload = function() {
// load the rest of the scripts here
var script2 = document.createElement('script');
script2.src='hhttp://documentcloud.github.com/backbone/backbone-min.js';
script2.type='text/javascript';
document.getElementsByTagName('Body').item(0).appendChild(script2);
}
document.getElementsByTagName('Body').item(0).appendChild(script1);
As far as i know that if a script tag is included, it will block further request
No, the blocking / synchronous download is only when the tags are right in the parsed HTML (or are inserted via document.write during the parse); dynamically DOM-appended scripts load asynchronously and in parallel.
To do that but ensure that scripts are executed when their dependencies are met, you need to use AMD loaders.
Here I have asked a question pertaining to exceptions raised when dynamically loading scripts via XMLHttpRequest (in other words when executed via eval)
In a related question, I wanted to know whether loading scripts dynamically as such is considered bad practice to begin with. In my particular case I have an HTML Canvas element, and rather than load all possible shapes, I want to fetch them dynamically, without reloading the page, and execute them on return. The problem I am having there is that if the code associated with that shape is incorrect, the error message displayed is not very useful (indicates location of eval statement, not incorrect statement). Is there another way to dynamically fetch code from the server and execute it, while better informing the location of the exception when it occurs.
If you want to load a script use a <script> element. If you want to dynamically load a script, create the <script> element dynamically.
var script = document.createElement('SCRIPT');
script.src = "<url to load>";
document.getElementsByTagName("HEAD")[0].appendChild(script);
It's not guaranteed to be synchronous the way eval with synchronous XHR is, but ideally you'd structure your code to take advantage of asynchony.
Adding to Mike's answer, if you want good debugger support including a script tag is probably the way to go, since that is what debuggers are used to working on. The main differences from eval that you need to be aware of are:
Eval runs in the scope of where its called while included script tags run in the global scope.
Eval is synchronous while included tags run asynchronously. (You will need to use something like JSONP and dojo.io.script if you need to run code after the script tag finishes).
If the scripts are fixed you can also consider debugging them by including their script tags and deploying them as you see fit.
I simply want to load a GWT(Google Web Toolkit) app by adding a script tag to the DOM, however because the GWT linker uses document.write() I'm unable to find any good way of doing so. I've found some hacks for doing so on various blog posts but they all seem to fail with the latest version of GWT. Any reasonably non-invasive approach for doing this come to mind?
Clarification:
Normal way to start up a GWT app, in your host html page:
<script type="text/javascript" language="javascript" src="myapp.nocache.js"></script>
This, of course, starts up as soon as the page loads. I want to do it at a later time:
function startapp() {
var head = document.getElementsByTagName('head');
var s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.setAttribute('src', 'myapp.nocache.js');
head[0].appendChild(s);
}
Here's what seems to work so far:
Add this to the top of your App.gwt.xml:
<!-- Cross site linker -->
<inherits name="com.google.gwt.core.Core" />
<add-linker name="xs" />
After compiling your app with the above setting, modify (or copy) the generated app.nocache.js as follows:
1) Comment the last $doc.write... statement
2) Copy this portion from the $doc.write statement you just commented out and eval it. Example:
eval('window.__gwtStatsEvent && window.__gwtStatsEvent({' + 'moduleName:"app", sessionId:window.__gwtStatsSessionId, subSystem:"startup",' + 'evtGroup: "loadExternalRefs", millis:(new Date()).getTime(),' + 'type: "end"});' + 'window.__gwtStatsEvent && window.__gwtStatsEvent({' + 'moduleName:"app", sessionId:window.__gwtStatsSessionId, subSystem:"startup",' + 'evtGroup: "moduleStartup", millis:(new Date()).getTime(),' + 'type: "moduleRequested"});');
3) Add this line right after.
document.body.appendChild(document.createElement('script')).src=base + strongName + ".cache.js";
So you're basically replacing the $doc.write with those two lines.
Now, your bookmarklet will look something like:
My App
I'm assuming you are already using the cross-domain linker and this does not resolve your problem with document.write. If not, it might be worth a look (sorry, not enough experience with it to say.)
One approach that I am fairly sure could be made to work is this:
Your bookmarklet adds a script tag to the page (as now)
This script is not GWT compiler output. It is a plain-old javascript that adds an IFrame to the page, and the src of that IFrame is pointed at an HTML page on your server that loads your GWT module.
Presumably the goal is for your GWT module to get things out of the page it was loaded into. Of course, it can't do this directly in this case because the IFrame comes from a different domain than the parent page.
In order to make this work you would have to use window.postMessage and window.addEventListener to communicate between your GWT module in the IFrame and your javascript stub in the parent (using JSNI on the GWT side.)
If you have to support older browsers, postMessage won't work - but you might be able to get away with hash manipulation - but this is probably where I'd draw a line on practicality.
Whenever a browser loads a javascript file, its also execute every line of it inorder to build the symbol tables etc.
In your case, the app loads in the browser and after the dom is loaded, your GWT module js gets loaded. At this point, the browser will try to execute every line of the GWT module javascript, possibly causing your earlier loaded DOM to go for a toss.
What exactly is your use case? If your requirement is conditionally loading the GWT module then your could try something like this:
Include this in your head:
<script src="gwtmoduleloader.js"></script>
Here, gwtmoduleloader.js is infact a servlet that will hold logic to figure out if the gwt module is to be loaded.
If the GWT module is to be loaded, the sevlet can print a
document.write('<script src="myapp.nocache.js"></script>')
or else return silently.
When browser evaluates the contents of gwtmoduleloader.js, it may find a document.write for another script (in your case the gwt module), which it will load and evaluate. This is thus a conditional load and can be achieved before the body begins loading.
Is this what you were looking for?