I'm using a sample project from here.
Suppose I need to export some function from my module to provide some JavaScript API to the clients of my service.
But the declarations in my .js files are not visible outside RequireJS!
I add the following block to jquery-require-sample/webapp/app.html:
<script type="text/javascript">
$(document).ready(function() {
$('body').alpha().beta();
});
</script>
It fails: Uncaught TypeError: Object [object Object] has no method 'alpha'.
Is it possible to do what I want?
Based on the code you provided I'm assuming you added your code after the existing script tag in app.html. I think what you're seeing is a timing issue. After you load the page, take a look at the <head> tag and you should see script tags in the following order:
the "require" script
your new script
alpha
beta
so it's running your script before the alpha and beta are run. The reason is because require will process the first script, but not execute the "meat" of main.js until all it's dependencies are run (alpha and beta).
I hope this helps. The following changes to your code may also illustrate what's going on. the setTimeout gives alpha and beta a chance to load:
<script type="text/javascript">
setTimeout(function(){
$(document).ready(function() {
$('body').alpha().beta();
});
}, 5000);
</script>
Related
I'm experimenting with the google closure library, and am working through the
official XhrIo guide.
I ran into some trouble with the xhr-quick2.js example, reproduced below:
goog.require('goog.net.XhrIo');
var xhr = new goog.net.XhrIo();
goog.events.listen(xhr, goog.net.EventType.COMPLETE, function(e) {
obj = this.getResponseJson();
log('Received Json data object with title property of "' +
obj['title'] + '"');
alert(obj['content']);
});
function getData(dataUrl) {
log('Sending simple request for ['+ dataUrl + ']');
xhr.send(dataUrl);
}
When run, I receive the error:
Uncaught TypeError: Cannot read property 'XhrIo' of undefined
If I move the event listener and xhr instantiation to within the getData
function (which is called in the body's onload), all is well.
goog.require('goog.net.XhrIo')
function getData(dataUrl) {
var xhr = new goog.net.XhrIo()
goog.events.listen(xhr, goog.net.EventType.COMPLETE, function(e) {
obj = this.getResponseJson()
log(`Received Json data object with title property of "${ obj["title"] }"`)
alert(obj["content"])
})
log(`Sending simple request for [${ dataUrl }]`)
xhr.send(dataUrl)
}
function log(msg) {
document.getElementById('log').appendChild(document.createTextNode(msg));
document.getElementById('log').appendChild(document.createElement('br'));
}
I assume this is because goog.require hasn't finished importing net when
goog.net.XhrIo is instantiated on line 3 of the first code sample. I suppose
the ideal solution is to run all my code through the closure compiler, but I'm
just experimenting and other parts of the
documentation
imply my workflow is acceptable for development.
Is there anything I can manually source in my html that would eliminate this
problem? Is there some other approach I should take?
It's been a few years since I last played with closure, but I don't think you can just use require without the dependency compiler.
Closure works by scanning your JavaScript files for goog.module and goog.require to write a deps.js file. This file has to be loaded first before your JavaScript files. It lists all the modules used by the code and loads them in the correct order.
If deps.js comes first, then goog.net will be loaded in by the time it gets to your code. The code goog.require('goog.net.XhrIo') on line 1 will at this time be ignored.
According to the docs the goog.require will insert a <script> tag after the current <script> being executed. So if you want to skip the step of using deps.js then you'll have to wrap everything in a document ready callback, or manaully add goog.require to a JavaScript file that is loaded before your code.
I think it's not worth the effort and easier to just use the closure dependency writer to create the deps.js file.
There's a quick tutorial here:
https://www.safaribooksonline.com/library/view/closure-the-definitive/9781449381882/ch01.html
Here's the CLI for writing the deps.js file:
python ../closure-library/closure/bin/calcdeps.py \
--dep ../closure-library \
--path my_stuff.js \
--output_mode deps > deps.js
For uncompiled mode, the required document must be pre-loaded. So in your html document you would have:
<!DOCTYPE html>
<html>
<head>
<script src="path/to/closure/base.js"></script>
<script>
goog.require('goog.net.XhrIo');
</script>
<script src="mysource.js"></script>
</head>
</html>
Any dependencies must be loaded in a separate script tag. Then your code samples above should work.
I'm playing around with Google Drive API, and noticed that they are calling a handleClientLoad function onload of the client.js.
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
Trying to avoid creating globals, I thought I would start with creating another js file, that would contain a module pattern and return handleClientLoad.
var module = (function (window, $) {
'use strict';
var module = {
handleClientLoad: function () {
console.log('ok, can access');
}
};
return module;
}(window, jQuery));
And then I assumed I could just call the handleClientLoad by doing module.handleClientLoad, but that doesn't seem to be working.
<script src="scripts/main.js"></script>
<script src="https://apis.google.com/js/client.js?onload=module.handleClientLoad"></script>
Questions:
Is it possible to call the module.handleClientLoad from onload of client.js?
Appending onload and calling a function from a script file seems sloppy and obtrusive, no? Is there a cleaner way to know when the client.js has loaded?
Have you tried debugger, and are you sure module. hanfleClientLoad exists at the time the callback is fired?
You can poll for the existence of gapi.client as a global object. Give it a few milliseconds to initialise before invoking its methods.
I found that jQuery.getScript() worked quite nicely for this. Documentation here.
Instead including the <script> tag in the html page, I simply included the following line in my js file:
jQuery.getScript( "https://apis.google.com/js/api.js", handleClientLoad );
It might require slight tweaking for the way you structured your module, but I think this will be easier than passing a parameter to your <script> tag (at least I found it easier).
I know this is old, but I was messing around with this because this was related to a question on a test I was studying for. You can use onload like this when you call the script:
<script src="https://apis.google.com/js/client.js" onload="handleClientLoad()"></script>
For anyone wanting to know why this won't work:
<script src="https://apis.google.com/js/client.js">handleClientLoad()</script>
It's because any code between a script tag with "src=" in it will be ignored.
And I'm not sure why using onload= in the script tag calling the external script is any more obtuse than appending ?onload=module.handleClientLoad to the source? But that's just me.
In the end, I'm not sure why exactly this was a question on the test, because based on searching, this doesn't seem to be a common thing that anyone does.
Why does a linked JavaScript file sometimes not work when it is included at the top of the page and not at the bottom?
<script type="text/javascript" src"..."></script>
For example, if you want to manipulate DOM items, and those are not yet existing, it won't work. If the JavaScript file is included in the head, the body is not existing yet, but if you include it at the end of the body, those items are valid.
If you don't want to rely on this behaviour, you may define a callback, which is run, when the document is ready, i.e. when the whole of the DOM is loaded already.
This is what e.g. jQuery achieves with $(document).ready(function() {}), or more shortly $(function () {});. In vanilla JavaScript (using modern browsers, so IE9+) this can be achieved using
document.addEventListener("DOMContentLoaded", function() {
// code...
});
The best way to know why is it not working is by checking for JS error. Try to find out what errors you are getting when the script has been included at the top. As mentioned in the other response it can be because of DOM items. You can circumvent this issue by adding a "defer" tag to the script.
It can also be because of some JS object you are expecting to be present when this script runs. For example if your script tag is serving a JSONP request then you must have the function that processes the data. Otherwise you will get a "undefined function" error when the script runs.
JS code is executed instruction by instruction from top to bottom.
The code that calls a function needs to be under that functions definition.
This code works:
var func = function()
{
alert('it works');
};
func();
While this doesn't:
func();
var func = function()
{
alert('it works');
};
It throws an undefined error. The reason for this is that JS compiler is not aware of the func definition at the time it tries to call it.
Same goes for the JS files included in your HTML page. You can include them at the bottom as long as there are not dependencies in above sections, or, if they do not try to manipulate HTML code before page load.
I've got a Closure environment running fine in my development environment. In a new folder & file, however, it is not working.
For example, take this test script:
goog.require('goog.dom');
console.log(goog);
console.log(goog.dom);
goog.dom.getElement('logout').innerHTML = "Heck";
That's all, plus the base.js in the HTML.
The first console.log shows an object with all the right stuff is in there. All the files are loaded into the DOM too.
The second console log, however, says undefined and so the last line doesn't work (obviously). The Chrome console error is Uncaught TypeError: Cannot call method 'getElement' of undefined.
What the heck is going on? It's the same if I try XhrIo. It's not finding the methods on the goog object.
Thanks.
Documentation:
Note: Do not put your goog.require() statements in the same script tag
as the entry point to code that uses the goog.required functions or
classes. A goog.require() call adds code to the document after the
script tag containing the call.
So
<script>
goog.require('goog.dom');
console.log(goog.dom);
</script>
prints undefined. But
<script>
goog.require('goog.dom');
</script>
<script>
console.log(goog.dom);
</script>
or
<script>
goog.require('goog.dom');
addEventListener('load', function() {
console.log(goog.dom);
});
</script>
prints an Object.
FYI, there are other possible workflows. For example, the closurebuilder.py script can help to load all the required files ahead of time.
I have a Dojo 1.7.4 app that is getting "Unable to get value of the property 'dir': object is null or undefined" error when loading pages in IE9.
I'm using an AMD build, and the error does not happen when it has to load all the files individually.
All the code that I have control over is wrapped in dojo/ready and dom/domReady! calls to the point of paranoia.
When the error occurs, and I catch it with the IE9 debugger, and Call stack reveals that the error occurs when calling isBodyLtr, but the top of the call stack is nls/synapse_en-gb.js. The nls/synapse_en-gb.js file seems to be the compile nls file with all the en-gb translations used by the application.
This seems to be getting loaded by virtue of having "en-gb" as my only locale entry in my dojoConfig, and I don't seem have control to ensure it is also wrapped in a dojo/ready or dojo/domReady!.
Here is the sample code in my HTML that bootstraps the Dojo package.
Any pointers for preventing the translation file from running until the dom and remaining Dojo files have fully loaded?
<script type="text/javascript">
//<![CDATA[
var dojoConfig = {
async: true,
parseOnLoad: true,
isDebug: true,
locale: "en-gb",
baseUrl: "/synapse/js/dojo/dojo/",
paths: {"synapse": "../../synapse"}
};
//]]>
</script>
<script type="text/javascript" src="/synapse/js/dojo/dojo/dojo.js"></script>
<script type="text/javascript">
//<![CDATA[
require(['dojo/ready', 'synapse/synapse', 'dojo/domReady!'], function(ready) {
ready(function () {
require(['dojo/ready', 'synapse/overlay','dojo/domReady!'], function (ready, package) {
ready(function() {
package.init();
});
});
});
});
//]]>
Update: 17 April 2013
To try and work out what function calls are in the stack trace, I bootstrapped from dojo.js.uncompress.js.
This shows me that nls/synapse_en-gb.js is the entry point, with calls to the var def = function() (which gets exposed in the global namespace as define, then checkComplete, then execModule and so forth.
Since this seems to run before the DOM is even loaded, I needs to find a way to ensure that nls/synapse_en-gb.js is not run until the DOM is loaded.
Looking at my generated synapse/synapse.js, there is a *now function at the base that appears to preload the i18n files file. i.e.
"*now":function(r){
r(["dojo/i18n!*preload*synapse/nls/synapse*[\"ar\",\"ca\",\"cs\",\"da\",\"de\",\"el\",\"en-gb\",\"en-us\",\"es-es\",\"fi-fi\",\"fr-fr\",\"he-il\",\"hu\",\"it-it\",\"ja-jp\",\"ko-kr\",\"nl-nl\",\"nb\",\"pl\",\"pt-br\",\"pt-pt\",\"ru\",\"sk\",\"sl\",\"sv\",\"th\",\"tr\",\"zh-tw\",\"zh-cn\",\"ROOT\"]"]);
}
I may end up having to relocate all the dojo loading until after so there's a much better chance of the DOM having been loaded, before dojo doing it's thing.
you can control the execution of the ready function by adding a number before the actual function:
ready(999999,function() {
package.init();
});
Small numbers mean early execution, big numbers late execution !
You have nested a ready function inside a ready function. I don't think their are ment to be used that way...
I ended up having to move the inline portion of the script to after the </body> tag.