How to load multiple template files using requireJs? - javascript

I am using Require JS to load vendor files and templates in JS.
I want to call one function when all related templates are loaded in page.
Currently I need to nested call like below:
requirejs(['text!templates/stream/leaderboard_m.ejs'], function(Leaderboard_M)
{
requirejs(['text!templates/stream/leaderboard_tl.ejs'], function(Leaderboard_TL) {
loadLeadrboardData(Leaderboard_M, Leaderboard_TL);
});
});
I would like to do that in 1 statement:
How can I do that using require JS?

Take a look at this: http://requirejs.org/docs/api.html#defdep
This would be what you want:
define([
"./services/MyFirstService",
"./services/MySecondService",
"./services/MyThirdService",
],
function (
MyFirstService,
MySecondService,
MyThirdService
) {
// all files loaded and can be used now!
});

You can reduce it to this:
requirejs(['text!templates/stream/leaderboard_m.ejs',
'text!templates/stream/leaderboard_tl.ejs'],
loadLeadrboardData);
All items in the list passed to the require (aka. requirejs) call are loaded before the callback is loaded. And the callback is loaded with the result of each item in the list of dependencies, in the same order. So you can have requirejs call loadLeadrboardData directly.
(I'd expect the function to be properly spelled loadLeaderboardData, not loadLeadrboardData with a missing e, but this is tangential to the problem asked here.)

Related

Using jQuery and RequireJS at start of processing

I often start my JavaScript apps like this:
jQuery(function($) {
... code for the app ...
});
I'm just starting to use RequireJS, and will start the app like this:
define(['jquery'], function($) {
... code for the app ...
});
Now, as I don't want the app to start processing until all the HTML has been loaded, I've combined the two like this:
require(['jquery'], function($) {
$(function($) {
... code for the app ...
});
});
Is that the way to do it?
The RequireJS documentation touches on this and offers has a slightly more convenient option:
require(['domReady!'], function (doc) {
//This function is called once the DOM is ready,
//notice the value for 'domReady!' is the current
//document.
});
Note that you will need to download the domReady plugin, and if you have a very complex page you may wish to use the "explicit function call" method that they also show... Although then it looks an awful lot like what you're already doing with jQuery.
So the main diferences between define and require in this scenario is, one declare a module and the second one call this defined module, then if it is not loaded, the browser download the js library.
To take control about when your require files will download, you need to use the domReady plugin.
You need to put the js library at you require.config, I usually put at the same directory as declared at the baseUrl property, for example:
require.config({
baseUrl: "js/lib",
paths:{
filter:"../src/filter",
addPanel: "../src/edit-panel"
}
}
I put the domReady.js at the js/lib/ folder.
So, then you can use the require method at any place of you html file:
require(['jquery!'], function ($) {
});
Note that I use the symbol ! to indicate that this library is load after the completely page load.
As the box at the top of the page, my question is answered here:
Requirejs domReady plugin vs Jquery $(document).ready()?
The other answers here essential repeat what's in the above link. But, thanks!

How can I combine my JavaScript files and still have my callbacks wait for a ready state?

I have lots of functions and event handlers that are split across multiple javascript files which are included on different pages throughout my site.
For performance reasons I want to combine all of those files into 1 file that is global across the site.
The problem is I will have event handlers called on elements that won't necessarily exist and same function names.
This is an example of a typical javascript file...
$(document).ready(function(){
$('#blah').keypress(function(e){
if (e.which == 13) {
checkMap();
return false;
}
});
});
function checkMap() {
// code
}
function loadMap() {
// code
}
I would need to seperate this code into an object that is called on that specific page.
My thoughts are I could re-write it like this:
(function($) {
$.homepage = {
checkMap: function(){
// code
},
loadMap: function(){
//code
}
};
})(jQuery);
And then on the page that requires it I could call $.homepage.checkMap() etc.
But then how would I declare event handlers like document.ready without containing it in it's own function?
First of all: Depending on how much code you have, you should consider, if serving all your code in one file is really a good idea. It's okay to save http-requests, but if you load a huge chunk of code, from which you use 5% on a single page, you might be better of by keeping those js files separated (especially in mobile environments!).
Remember, you can let the browser cache those files. Depending on how frequent your code changes, and how much of the source changes, you might want to separate your code into stable core-functionality and additional .js packages for special purposes. This way you might be better off traffic- and maintainance-wise.
Encapsulating your functions into different objects is a good idea to prevent unnecessary function-hoisting and global namespace pollution.
Finally you can prevent calling needless event handlers by either:
Introducing some kind of pagetype which helps you decide calling only the necessary functions.
or
checking for the existence of certain elements like this if( $("specialelement").length > 0 ){ callhandlers}
to speed up your JS, you could use the Google Closure Compiler. It minifies and optimizes your code.
I think that all you need is a namespace for you application. A namespace is a simple JSON object that could look like this:
var myApp = {
homepage : {
showHeader : function(){},
hideHeader : function(){},
animationDelay : 3400,
start : function(){} // the function that start the entire homepage logic
},
about : {
....
}
}
You can split it in more files:
MyApp will contain the myApp = { } object, maybe with some useful utilities like object.create or what have you.
Homepage.js will contain myApp.homepage = { ... } with all the methods of your homepage page.
The list goes on and on with the rest of the pages.
Think of it as packages. You don't need to use $ as the main object.
<script src="myapp.js"></script>
<script src="homepage.js"></script>
<-....->
<script>
myApp.homepage.start();
</script>
Would be the way I would use the homepage object.
When compressing with YUI, you should have:
<script src="scripts.min.js"></script>
<script>
myApp.homepage.start();
</script>
Just to make sure I've understood you correctly, you have one js file with all your code, but you want to still be in control of what is executed on a certain page?
If that is the case, then the Terrific JS framework could interest you. It allows you to apply javascript functionality to a module. A module is a component on your webpage, like the navigation, header, a currency converter. Terrific JS scans the dom and executes the js for the modules it finds so you don't have to worry about execution. Terrific JS requires OOCSS naming conventions to identify modules. It's no quick solution to your problem but it will help if you're willing to take the time. Here are some more links you may find useful:
Hello World Example:
http://jsfiddle.net/brunschgi/uzjSM/
Blogpost on using:
http://thomas.junghans.co.za/blog/2011/10/14/using-terrificjs-in-your-website/
I would use something like YUI compressor to merge all files into one min.js file that is minified. If you are looking for performance both merging and minifiying is the way to go. http://developer.yahoo.com/yui/compressor/
Example:
Javascript input files: jquery.js, ads.js support.js
run yui with jquery.js, ads.js, support.js output it into min.js
Javascript output files: min.js
then use min.js in your html code.

How to manage dependencies in JavaScript?

I have scripts that needs to wait for certain conditions to be met before they run - for example wait for another script to be loaded, or wait for a data object to be created.
How can I manage such dependencies? The only way I can think of is to use setTimeout to loop in short intervals and check the existence of functions or objects. Is there a better way?
And if setTimeout is the only choice, what is a reasonable time interval to poll my page? 50 ms, 100 ms?
[Edit] some of my scripts collect data, either from the page itself or from Web services, sometimes from a combination of multiple sources. The data can be ready anytime, either before or after the page has loaded. Other scripts render the data (for example to build charts).
[update] thanks for the useful answers. I agree that I shouldn't reinvent the wheel, but if I use a library, at least I'd like to understand the logic behind (is it just a fancy timeout?) to try and anticipate the performance impact on my page.
You could have a function call like loaded(xyz); at the end of the scripts that are being loaded. This function would be defined elsewhere and set up to call registered callbacks based on the value of xyz. xyzcan be anything, a simple string to identify the script, or a complex object or function or whatever.
Or just use jQuery.getScript(url [, success(data, textStatus)] ).
For scripts that have dependencies on each other, use a module system like RequireJS.
For loading data remotely, use a callback, e.g.
$.get("/some/data", "json").then(function (data) {
// now i've got my data; no polling needed.
});
Here's an example of these two in combination:
// renderer.js
define(function (require, exports, module) {
exports.render = function (data, element) {
// obviously more sophisticated in the real world.
element.innerText = JSON.stringify(data);
};
});
// main.js
define(function (require, exports, module) {
var renderer = require("./renderer");
$(function () {
var elToRenderInto = document.getElementById("#render-here");
$("#fetch-and-render-button").on("click", function () {
$.get("/some/data", "json").then(function (data) {
renderer.render(data, elToRenderTo);
});
});
});
});
There are many frameworks for this kind of thing.
I'm using Backbone at the moment http://documentcloud.github.com/backbone/
Friends have also recommended knockout.js http://knockoutjs.com/
Both of these use an MVC pattern to update views once data has been loaded by a model
[update] I think at their most basic level these libraries are using callback functions and event listeners to update the various parts of the page.
e.g.
model1.loadData = function(){
$.get('http://example.com/model1', function(response){
this.save(response);
this.emit('change');
});
}
model1.bind('change',view1.update);
model1.bind('change',view2.update);
I've used pxLoader, a JavaScript Preloader, which works pretty well. It uses 100ms polling by default.
I wouldn't bother reinventing the wheel here unless you need something really custom, so give that (or any JavaScript preloader library really) a look.

What's the best way to execute something only when all my JavaScript is loaded using jQuery?

I'm developing a web page using jQuery, and I want it to execute some code only after ALL my JavaScript files are fully loaded. The head section of my HTML has the following script.
<script src="supervisor/lib/jquery-1.6.min.js" type="text/javascript"></script>
Inside jQuery file, I inserted the following code:
$.getScript('functions.js', function () {
// code here
});
The file functions.js has the following code:
$.getScript('mask.js');
$.getScript('validations.js');
$.getScript('lotsofscripts.js');
// and more...
I want the code here in the first $.getScript() to execute only after ALL the other JS are loaded, but this is not ocurring. What's the best way to achieve this?
PS: I'm using lots of $.getScript() because I find easier to separate them, but I want them to be inserted inside the same file.
You could always just increment a counter. That way your getScript calls remain asynchronous, as the last thing you want to do is change that. And frankly, any packaged solution you find to loading the scripts in parallel and then executing some function afterward will probably just be a shinier version of this:
var counter = 0;
var filesToLoad = ["mask.js", "validations.js", "lotsofscripts.js"];
var filesCount = filesToLoad.length;
// Increment counter each time a getScript completes
function incrementCounter() {
if (++counter === filesCount) {
// This code will execute after everything loads
}
}
// Iterate through the files and run getScript on them,
// with incrementCounter as the callback
for (var i = 0; i < filesCount; i++) {
$.getScript(filesToLoad[i], incrementCounter);
}
Here's a jsFiddle example.
Assuming you know the name of a function defined in a js script that needs to be tested for whether or not it has loaded...
I use Underscore.js isFunction() to figure this out ( http://documentcloud.github.com/underscore/#isFunction )
Example, if script.js contains a function myScriptFunction(), you can write a function that checks:
if (_.isFunction(myScriptFunction)) {
// script.js is loaded
// OK to move on to the next step
} else {
// script.js is not loaded
// check again later
}
I have tried binding to events to figure out if a js script file is loaded, but it doesn't seem to work across all the browsers.
I would suggest HeadJS to load your JS files. You can execute specific code upon completion of specific files or groups of files. Take a look, it's a great little project.
You might want to use jQuery.ajax() instead. You can set the async option to false (it's true by default when you use getScript

RequireJS Flawed By Example?

Looking into RequireJS but unlike Head.JS which downloads in undetermined order but evaluates in a determine order, RequireJS seems different
Normally RequireJS loads and evaluates scripts in an undetermined order.
Then it shows how to prefix order! to the script names for explicit ordering etc..
Then in the examples:
require(["jquery", "jquery.alpha", "jquery.beta"], function($) {
//the jquery.alpha.js and jquery.beta.js plugins have been loaded.
$(function() {
$('body').alpha().beta();
});
});
So if jquery.alpha is downloaded and evaluated before jquery then surely this would cause a problem? Forgetting any client code usage such as function body above, if like most plugin they attach to jQuery.fn then at stage of evaluation then jQuery will undefined in this scenario.
What am I missing here?
RequireJS is not designed to load plain javascript, but to load defined modules. The module format looks something like:
define(['a', 'b'], function(a, b) {
return { zzz: 123 };
});
The important thing to note is that all of the module code is inside an anonymous function. So if the file is run in an arbitrary order, it doesn't matter, because all it does is register the module. The module code is then run in dependency order, with the return value becoming the module object, which is passed as a parameter to code that uses the module.
If you are trying to load plain files, this will not work correctly for you. There is the order plugin to force load order in that case.
It should be noted that that example uses the custom made version of "requirejs and jquery" packaged together, which I believe means that jquery will always be available first.
If you have problems, you can always wrap your plugins within a module definition and make sure they depend on jquery themselves, again ensuring the order is correct:
/* SPECIAL WRAPPING CODE START */
define(['jquery'], function(jQuery) {
// .... plugin code ....
/* SPECIAL WRAPPING CODE END */
});
You are correct, without something to aid in the order an exception will occur. The good news is RequireJS has an Order plug-in to help in this.
I'm currently evaluating RequireJS...
And Here Is An Example of One of My Files:
The 'order!' command will load files for you sequentially. You can (then) use the callback to load other (support) files.
<script src="Loaders/RequireJS/requireJS.js" type="text/javascript"></script>
<script src="Loaders/RequireJS/order.js" type="text/javascript"></script>
<script type="text/javascript">
require(["Loaders/RequireJS/order!././Includes/JavaScript/jQuery/Core/jquery-1.3.2.js",
"Loaders/RequireJS/order!././Includes/JavaScript/jQuery/Core/jquery.tools.min.js",
"Loaders/RequireJS/order!././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tmpl.js"], function() {
require(["././Includes/JavaScript/jQuery/jGeneral.js",
"././Includes/JavaScript/jQuery/autocomplete.js",
"././Includes/JavaScript/jQuery/jquery.ErrorWindow.js",
"././Includes/JavaScript/jQuery/jquery.ValidationBubble.js",
"././Includes/JavaScript/jQuery/jquery.Tootltip.js",
"././Includes/JavaScript/jQuery/jquery.Extensions.js",
"././Includes/JavaScript/jQuery/jquery.Toaster.js"], null);
require(["././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.dimensions.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jQuery.Color.Animations.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.corners.min.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tipsy.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.numberformatter-1.1.0.js",
"././Includes/JavaScript/jQuery/ThirdPartyPlugIns/jquery.tipsy.js"], null);
});
</script>
In All Honesty:
I'm looking at various asynchronous resource-loaders and I'm having a hard-time finding one that does everything I need. I'm also finding the documentation in each one lacking.

Categories

Resources