In Addy Osmani's ToDo MVC example for require.js + Backbone: https://github.com/addyosmani/todomvc/blob/gh-pages/dependency-examples/backbone_require/js/main.js, he's using
Backbone.history.start() // line #31
without actually requiring Backbone. How/why does this work? Is the shim enabling this? Or am I missing something obvious?
If you have a look in the code, view/app.js is actually requiring Backbone.
And the backbone shim is exporting the global Backbone variable.
If no other modules will actually require the shim, it won't be loaded, so it won't be accessible.
You can try to remove the 'views/app' requirements in main.js to see for yourself.
As #ChristiMihai mentioned, Backbone created a global Backbone object, correct. Let me give you an example of what I do in my Require.js / Backbone / Handlebars app:
First, I include Require config in <head>:
var require_config = {
baseUrl: "/javascripts",
waitSeconds: 5,
paths: {
'cdnjs': 'http://ajax.cdnjs.com/ajax/libs',
'aspnetcdn': 'http://ajax.aspnetcdn.com/ajax',
'cloudflare': 'http://cdnjs.cloudflare.com/ajax/libs',
'local': '/javascripts'
}
}
if (typeof require !== 'undefined') {
require.config(require_config);
} else {
var require = require_config;
}
After that I bootstrap a require module, e.g:
define([
'app'
],
function() {
console.log('Homepage module');
/*
... this is the meat of your app...
you can add other dependencies beside `app` too
*/
});
Now app is the main dependency which resolves via baseUrl to /javascripts/app.js and includes all necessary deps in order, and looks like this:
define([
'order!cdnjs/json2/20110223/json2',
'order!cloudflare/underscore.js/1.3.1/underscore-min',
'order!cloudflare/backbone.js/0.9.2/backbone-min',
'order!handlebars/handlebars-1.0.0.beta.6.min',
'order!lib/ns',
'bootstrap'
], function(){});
Related
I am creating a NodeJS app which uses AngularJS for it's front-end. I am Also using RequireJS to load in the JS dependencies and then instantiate the Angular app. Here is what I am trying to do:
Within my HTML file (written in Jade) I include the RequireJS files and then call the RequireJS config using the 'data-main' attribute:
doctype html
html
head
title= title
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content
script(type="text/javascript" src="/bower_components/requirejs/require.js" data-main="/main.js")
My main.js file looks as follows:
"use strict";
function(require) {
require(['/assets/requiredPathsAndShim.js'], function(requiredPathsAndShim) {
require.config({
maps : {
// Maps
},
paths : requiredPathsAndShim.paths,
shim : {
// Modules and their dependent modules
}
});
angular.bootstrap(document, ['appNameInHere']);
});
})(require);
I have an external file which contains an object with my routes '/assets/requiredPathsAndShim.js' and it looks like follows:
"use strict";
(function(define) {
define([], function() {
return {
paths : {
'angular' : '/bower_components/angular/angular'
}
};
});
})(define);
I will add that my NodeJS/Express app has the 'bower_components' folder set to serve static files and this is working fine.
Whenever I try and instantiate the AngularJS app using the 'angular.bootstrap...' method it tells me Angular is not defined. I can't see why this is happening and haven't been able to figure it out yet. O can't see any problem with my routes to the Angular files. Can anyone see or suggest why this may be happening?
Thanks!
Just managed to crack it! I had to place the 'angular.bootstrap' call in a callback function of the require.config method as the app was trying to call AngularJS before it had been defined.
Hope this helps anyone in the future.
In my project, I hope the lazy loaded modules can add their own state, so I found the ui-router-extras. It's really useful for me, but when I want to use ng-grid in the lazy loaded module like the module1 in demo, the module1.js file looks like this:
define(['angularAMD', 'ngGrid'], function () {
var app = angular.module("module1", ['ui.router','ngGrid']);
...
and the main.js file looks like this:
require.config({
waitSeconds: 100,
paths: {
"angularAMD": "../../lib/angularAMD",
...
"jQuery": "../../lib/jquery",
"ngGrid": "../../lib/ng-grid-2.0.14.debug"
},
shim: {
"angular": { exports: "angular" },
...
"ngGrid": ["angular", "jQuery"],
},
deps: ["app"]
});
But I got an exception from ng-grid : "Uncaught TypeError: Cannot read property 'factory' of undefined". I found the ng-grid source code where the exception happened:
angular.module('ngGrid.services').factory('$domUtilityService',['$utilityService', '$window', function($utils, $window) {....}
So I found in the lazy loaded module, get module by angular.module('mymodule') returns the undefined. Is there something I forgot to write, or is there another way to use ng-grid or other plugin in the lazy load module with ui-router-extras future?
You need to use the 'ngload' plugin for AngularAMD to load a module on the fly.
Excerpt from the docs:
3rd Party AngularJS Modules
3rd party AngularJS modules, meaning any module created using angular.module syntax, can be loaded as any normal JavaScript file before angularAMD.bootstrap is called. After bootstraping, any AngularJS module must be loaded using the included ngload RequireJS plugin.
define(['app', 'ngload!dataServices'], function (app) {...});
In case you need to load your module using the RequireJS plugin or if you have complex dependecies, you can create a wrapper RequireJS module as below:
define(['angularAMD', 'ui-bootstrap'], function (angularAMD) {
angularAMD.processQueue();
});
In this case, all dependencies will be queued up and when .processQueue() is called, it will go through the queue and copy them into current app using app.register:
https://github.com/marcoslin/angularAMD
i have a weird problem regarding angular resource. when i try to define it it causes the app to create an error. i dunno but is this the correct style of defining an angular Resource? tIA
main.js
'use strict';
require.config({
paths: {
jquery: 'libs/jquery/jquery-1.9.1',
angular: 'libs/angular/angular.min',
ngResource: 'libs/angular/angular-resource.min'
},
shim: {
angular: {
exports: 'angular'
},
resource : { deps : ['angular'], 'exports' : 'ngResource'},
}
});
require([
'jquery',
'angular',
//'ngResource',
'app',
'routes',
],
function ($, angular, app, routes) {// set main controller
$(function(){
var $html = $('html');
angular.bootstrap($html, [app['name']]);
$html.addClass('ng-app');
});
});
Just to help out those users who are not familiar with the code above; The code shows RequireJS configuration and initialization structure, and only a small part at the end is the actuall AngularJS code.
You have correctly configured RequireJS to include ngResource before initialization, but you didn't actually tell Angular to use it.
I'm not sure what app['name'] stands for, but your angular bootstrap call should include the ngResource module:
angular.bootstrap($html, ['ngResource']);
And, btw, I don't think you need to add the class ('ng-app') at the end.
In your callback when all resources are loaded, try to explicitly define the modules and dependancies before bootstrapping, like this:
angular.module('fooApp', ['ngResource']); // Module name and list of dependancies.
angular.bootstrap(document, 'fooApp');
There is no need to manually add the ng-app class, when this class is used to do bootraping automatically, witch is not what you want. You want to load the applicatiopns module when all scripts are loaded, with the ngResource module as a dependancy.
Hope this helps.
Doing my first backbone app and I'm using a structure somewhat like this tutorial
I'm wondering where the correct place for me to put my onload code, such as setting up onclick listeners etc would be?
I have:
A simple Bootstrap
require.config({
paths: {
jquery: 'libs/jquery/jquery',
underscore: 'libs/underscore/underscore',
backbone: 'libs/backbone/backbone'
}
});
require([
// Load our app module and pass it to our definition function
'app',
], function(App){
// The "app" dependency is passed in as "App"
App.initialize();
});
The App.js
define(['routers/search'], function(router){
var initialize = function(){
this.router = new router();
}
return { initialize: initialize};
});
And then a simple router that calls the relevenent function in the router also defined as a module that calls the relevent function on the router depending on the page.
My feeling is that this function in the router is where I should be putting my onload code. Is that correct?
One possibility is to use the RequireJS domReady plugin (it's available for download from their short plugins list): http://requirejs.org/docs/api.html#pageload
Here's the example they give:
require(['domReady'], function (domReady) {
domReady(function () {
//This function is called once the DOM is ready.
//It will be safe to query the DOM and manipulate
//DOM nodes in this function.
});
});
So then you can just incorporate it into your normal RequireJS structure, knowing that both the DOM is loaded plus any additional dependencies you might have listed alongside it.
I've been messing around with a backbone.js app using require.js and a handlebars templates (I've added the AMD module stuff to handlebars) and just read that pre-compiling the templates can speed it up a fair bit.
I was wondering how I would go about including the precompiled templates with requirejs. I have a fair few templates to compile (upwards of 15), so i'm not sure if they should all be in the same output file or have their own once compiled. Also, from what it seems, the compiled templates share the same Handlebars namespace that the renderer script uses, so I'm not sure how I would go about that when requiring the templates in my files.
Any advice would be awesome!
A simple approach is to create a RequireJS plugin based on the existing text! plugin. This will load and compile the template. RequireJs will cache and reuse the compiled template.
the plugin code:
// hbtemplate.js plugin for requirejs / text.js
// it loads and compiles Handlebars templates
define(['handlebars'],
function (Handlebars) {
var loadResource = function (resourceName, parentRequire, callback, config) {
parentRequire([("text!" + resourceName)],
function (templateContent) {
var template = Handlebars.compile(templateContent);
callback(template);
}
);
};
return {
load: loadResource
};
});
configuration in main.js:
require.config({
paths: {
handlebars: 'libs/handlebars/handlebars',
hb: 'libs/require/hbtemplate',
}
});
usage in a backbone.marionette view:
define(['backbone', 'marionette',
'hb!templates/bronnen/bronnen.filter.html',
'hb!templates/bronnen/bronnen.layout.html'],
function (Backbone, Marionette, FilterTemplate, LayoutTemplate) {
...
In case you use the great Backbone.Marionette framework you can
override the default renderer so that it will bypass the builtin
template loader (for loading/compiling/caching):
Marionette.Renderer = {
render: function (template, data) {
return template(data);
}
};
Have a look at the Requirejs-Handlebarsjs plugin: https://github.com/SlexAxton/require-handlebars-plugin