Angular + Requirejs - Loading in the wrong order - javascript

I'm trying to have angular and jquery loaded with requirejs. The best I can do is that 50% of the time everything loads correctly, the other half I get the error No Module: mainApp
I'm assuming this is breaking half the time based on the speed on which requirejs is asynchronously loading the scripts.
When it works, I see the "Hello World" test (although I do see {{text}} flash before it is replaced, but I've been reading how to fix that here). The rest of the time I get the error and {{text}} just stays on the screen.
Github Repo
Tree:
index.html
- js
- libs
require.js
- modules
mainApp.js
main.js
main.js
require.config({
paths: {
'jQuery': '//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min',
'angular': '//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular',
},
shim: {
'angular' : {'exports' : 'angular'},
'jQuery': {'exports' : 'jQuery'}
}
});
require(['jQuery', 'angular', 'modules/mainApp'] , function ($, angular, mainApp) {
$(function () { // using jQuery because it will run this even if DOM load already happened
angular.bootstrap(document, ['mainApp']);
});
});
modules/mainApp.js
define(['angular'], function (angular) {
return angular.module('mainApp' , []).controller('MainCtrl', ['$scope', function ($scope) {
$scope.text = 'Hello World';
}]);
});
Relevant index.html
<head>
<script src="js/libs/require.js" data-main="js/main"></script>
</head>
<body>
<div ng-app="mainApp">
<div ng-controller="MainCtrl">
{{text}}
</div>
</div>
</body>

You can use domReady (UPDATED) to make sure that the DOM is fully loaded, i.e. all JS files are there, before bootstrapping your application.
requirejs.config({
paths: {
jquery: '/path/to/jquery',
angular: 'path/to/angular',
domReady: '/path/tp/domReady'
}, shim: {
angular: {
exports: 'angular'
},
}
});
define(['jquery', 'angular', 'modules/mainApp'],
function($, angular, 'mainApp') {
// tell angular to wait until the DOM is ready
// before bootstrapping the application
require(['domReady'], function() {
angular.bootstrap(document, ['mainApp']);
});
});
See the RequireJS official documentation for more information on this gotcha:
It is possible when using RequireJS to load scripts quickly enough
that they complete before the DOM is ready. Any work that tries to
interact with the DOM should wait for the DOM to be ready.
The trick is found on this blog post.
EDIT If you follow the blog post's advice, please use this domReady script instead of the one I previously posted: https://github.com/requirejs/domReady/blob/master/domReady.js.

Add Jquery as a dependency for Angular in the shim.
require.config({
paths: {
'jQuery': '//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min',
'angular': '//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular',
},
shim: {
'angular' : {'exports' : 'angular', deps: ['jQuery']},
'jQuery': {'exports' : 'jQuery'}
}
});

This might be a late response but as Dustin Blake said, you can also use jQuery .ready() instead of including another module like domReady.
requirejs.config({
paths: {
jquery: '/path/to/jquery',
angular: 'path/to/angular'
}, shim: {
angular: {
exports: 'angular'
},
}
});
require(['jquery'], function($) {
$(document).ready(function(){
// I like it this way instead of including
// everything in the parent function so it's easier to read
require(['angular', "modules/mainApp"], function(){
angular.bootstrap(document, ['mainApp']);
})
})
});

Related

"$.widget is not defined" after requirejs build

I'm using requirejs to load jquery.selectBoxIt. It uses the jQueryUI Widget factory, which is why I only loaded the widget factory from the jQueryUI official site into my project.
When the project is loaded with config.js, selectBoxIt runs without problems. But when I build the project with r.js, I get the error $.widget is not defined.
Please help me please fix it.
PS. I already read some Google results on it, but nothing helps.
config.js
require.config({
paths: {
'jquery': 'assets/libs/jquery/2.2.0/jscript/jquery.min',
'jquery.migrate': 'assets/libs/jquery/plugins/migrate/1.2.1/jscript/migrate.min',
'jquery.ui': 'assets/libs/jquery.ui/1.12.0/jscript/jquery-ui',
'jquery.selectboxit': 'assets/libs/jquery/plugins/selectboxit/3.8.1/jscript/selectBoxIt',
},
shim: {
'jquery.migrate': {
deps: ['jquery'],
exports: 'jQuery',
},
'jquery.selectboxit': {
deps: ['jquery.migrate', 'jquery.ui'],
},
},
});
module.js
define([
'jquery.selectboxit',
], function (SelectBoxIt) {
...
});
Error appear in selectBoxIt code in line
$.widget("selectBox.selectBoxIt", {

What does requirejs.config() do?

I am having trouble understanding about requirejs.config() function.
requirejs.config({
paths: {
'text': '../lib/require/text',
'durandal':'../lib/durandal/js',
'plugins' : '../lib/durandal/js/plugins',
'transitions' : '../lib/durandal/js/transitions',
'knockout': '../lib/knockout/knockout-3.1.0',
'bootstrap': '../lib/bootstrap/js/bootstrap',
'jquery': '../lib/jquery/jquery-1.9.1'
},
shim: {
'bootstrap': {
deps: ['jquery'],
exports: 'jQuery'
}
}
});
What does the function do? Please do not direct me to the documentation because I have read it and still found it confusing. I need a simple explanation on what this function does.
Are these scripts loaded asynchronously?
It creates aliases for script paths ant tells how to interpret bootstrap (non-AMD script) when loaded. Nothing is loaded yet. You have to require:
// we load two dependencies here
// `knockout` and `bootstrap` are expanded to values in config
// .js added to values
// callback function called when all dependencies are loaded
require(['knockout', 'bootstap'], function(Knockout, $) {
// jQuery is passed to this function as a second parameter
// as defined in shim config exports
});
The path is like declarations/definitions. So for example,
jquery: '../bower_components/jquery/dist/jquery',
you can later load this lib as follows.
define([
'jquery'
], function (jquery) {
//initialize or do something with jquery
}
You don't have to specify the absolute path of the library.
In shim, you will define dependencies. So for example,
paths: {
template: '../templates',
text: '../bower_components/requirejs-text/text',
jquery: '../bower_components/jquery/dist/jquery',
backbone: '../bower_components/backbone/backbone',
underscore: '../bower_components/underscore/underscore',
Router: 'routes/router'
},
shim: {
'backbone': ['underscore', 'jquery'],
'App': ['backbone']
}
Here backbone is dependent on underscore and jquery. So those two libs will be loaded before backbone starts loading. Similarly App will be loaded after backbone is loaded.
You might find this repo useful if you are familiar with backbone and express.
https://github.com/sohel-rana/backbone-express-boilerplate

RequireJS - custom js-library not working

I'm trying to include a custom js-library/script in my RequireJS-config but it doesnt seem to work. So I hope someone can help me out. I'm using RequireJS in combination with Backbone and Handlebars, so just to mention it...
In my Require config I have:
require.config({
paths: {
jquery: 'lib/jquery/jquery',
backbone: 'lib/backbone/backbone',
// Templating.
handlebars: 'lib/handlebars/handlebars',
// Plugins.
jqueryEffects: 'lib/jquery/jquery.effects',
... //some more libraries
},
shim: {
backbone: {
deps: ['jquery', 'lodash','jqueryEffects'],
exports: 'Backbone'
},
lodash: {
exports: '_'
},
handlebars: {
exports: 'Handlebars'
},
jqueryEffects : {
deps: ['jquery']
}
}
});
The jquery.effects.js is a simple script i created my own to handle special click events or run animations etc. When i start to run my backbone app, the console tells me that the script is loaded. So now on one of my Views, I have rendered a HTML file which contains an anchor with a class which serves as an identifier, which after clicking it should trigger something...BUT, nothing happens, so I tried to make an alert in the jquery.effects.js-file:
$(function() {
alert($(".videoname").lenght);
});
This gave me the response undefined. Does anyone maybe have an idea? The same goes when I add more libraries, console says they are loaded, but nothing happens... ?!?!?!??
try this (length not lenght) :
(function() {
alert($(".videoname").length);
})();
That's means that your script is working ;)

load javascript file before onload with requirejs

I would like to use requireJS. However, I have a lib that needs to be loaded before the DOM. However, this is not what happens with requireJS
<html>
<head>
<script data-main="/app" src="/require.js"></script>
</head>
<body>
<bar-foo/>
</body>
</html>
With app.js
require.config({
paths: {
'customElement': '/customElement',
'barfoo': '/barfoo'
},
shim: {
barfoo: {
deps: [ 'customElement' ]
}
}
});
define(['barfoo'], function() {
....
}
For example, if I simply load this script directly in the head (without requireJS) it works fine. Is there a require-config-option so I can load a specific file immediately (synchronously?) ?
Requirejs is known for it's asynchronous power. However when you need some sort of an order in which you want files to be loaded due to dependencies, in require.config there is a shim config:
shim: Configure the dependencies, exports, and custom initialization for older, traditional "browser globals" scripts that do not use define() to declare the dependencies and set a module value.
So let's say you have a backbone app that depends on Underscore and jQuery, and you want them to load in that order then your would:
require.config({
paths: {
'Backbone': '/Backbone',
'Underscore': '/Underscore',
'jQuery': '/jQuery'
},
shim: {
'Backbone': [ 'Underscore', 'jQuery' ]
}
});
require(['Backbone'], function(Backbone){
//.....
});
So, RequireJS allows us to use the shim config to define the sequence of files which need to be loaded in correct order.

How to use the domReady requireJS plugin correctly

Here is my main.js before using domReady:
require.config({
paths : {
loader : 'libs/backbone/loader',
jQuery : 'libs/jquery/jquery-module',
Underscore : 'libs/underscore/underscore-module',
Backbone : 'libs/backbone/backbone-module',
templates : '../Templates'
}
});
require([ 'app' ], function(app) {
app.initialize();
});
And app.js:
define([ 'jQuery', 'Underscore', 'Backbone', 'router',
'services/Initializers/MainFrameInitializer',
'services/Initializers/FlowsViewsInitializer',
'services/Initializers/EditModuleInitializer',
'services/Sandboxes/ModulesNavigationSandbox',
'services/Sandboxes/ApplicationStateSandbox', 'DataModel/Constants' ],
function($, _, Backbone, Router, MainFrameInitializer,
FlowsViewsInitializer, EditModuleInitializer, ModulesNavigationSandbox,
ApplicationStateSandbox, Constants) {
var initialize = function() {
// Pass in our Router module and call it's initialize function
MainFrameInitializer.initialize();
FlowsViewsInitializer.initialize();
EditModuleInitializer.initialize();
ApplicationStateSandbox.startCheckStatus();
ModulesNavigationSandbox.navigate(Constants.Modules.Home);
// Router.initialize();
};
return {
initialize : initialize
};
});
All works fine until I optimize the project. I have figured out, that the script starts to run before the DOM is ready, something that was not true before the optimization. Anyway, I wish to use the domReady plugin to make sure the DOM is loaded first.
But, apparently, I have no idea how to do it correctly. Here is the new version of main.js:
require.config({
paths : {
loader : 'libs/backbone/loader',
jQuery : 'libs/jquery/jquery-module',
Underscore : 'libs/underscore/underscore-module',
Backbone : 'libs/backbone/backbone-module',
templates : '../Templates'
}
});
require([ 'domReady', 'app' ], function(domReady, app) {
domReady(app.initialize);
});
Very neat and very wrong, because app is loaded in parallel with domReady before the DOM is ready.
How do I fix it?
Thanks.
EDIT
I think I have understood our problem. The constructor functions of the app dependencies should not run any DOM dependent code. They should just return functions, capturing the DOM dependent logic. That logic should be executed from app.initialize, which is guaranteed to be run when the DOM is ready.
Perhaps I am missing something, but wouldn't you make your life a lot easier by doing:
require(['jQuery', 'app' ], function(jQuery, app) {
jQuery(function ($) {
app.initialize();
});
});
in your main.js?
By requiring the app from inside the domReady callback function, you should be able to require the domReady module, and then the app module synchronously.
define(['require', 'domReady'], function(require, domReady) {
domReady(function() {
require(['app'], function(app) {
app.initialize();
});
});
});
If you follow the doc at: http://requirejs.org/docs/jquery.html, you will be invited to embed a require-jquery library in the head of your document:
<script data-main="main" src="libs/require-jquery.js"></script>
However, if you look at the source for the example, made available on github, you will see that 'require-jquery.js' is generated by simple concatenation of the require lib file and the jquery lib file:
cat require.js jquery.js > ../jquery-require-sample/webapp/scripts/require-jquery.js
That means that you could replace the script embed in the head part with the following script embeds anywhere in your document (for instance at the very bottom of it).
<script src="libs/require.js"></script>
<script src="libs/jquery-1.8.0.js"></script>
<script>require(["main"]);</script>
Because the jquery lib defines itself as a module with:
define( "jquery", [], function () { return jQuery; } );
You can thereafter use jquery as a require reference in any of your script. For instance:
require(["jquery"], function($) { }

Categories

Resources