Requirejs dependency not working - javascript

I am trying to use angular-ladda directive in my app. Here is my main.js which is the requirejs manifesto file:
requirejs.config({
paths: {
underscore: 'lib/underscore/underscore',
angular: 'lib/angular/angular',
jquery: 'lib/jquery/dist/jquery.min',
'angular-route': 'lib/angular-route/angular-route',
'controllers': 'js/controllers',
'services': 'js/services',
'providers': 'js/providers',
'filters': 'js/filters',
'directives': 'js/directives',
'app': 'js/app',
'spin': 'lib/ladda/dist/spin.min',
'ladda': 'lib/ladda/js/ladda',
'ngLadda': 'lib/angular-ladda/src/angular-ladda'
},
shim: {
underscore: {
exports: '_'
},
'angular': {
exports: 'angular'
},
'states': {
deps: ['angular'],
exports: 'states'
},
'angular-route': {
deps: ['angular']
},
'ladda': {
deps: ['spin'],
exports: 'Ladda'
},
'ngLadda': {
deps: ['ladda']
}
},
priority: [
'angular'
]
});
requirejs(['angular',
'app',
'underscore',
'js/routes',
'jquery',
'services/services',
'providers/providers',
'directives/directives',
'filters/filters',
'controllers/controllers',
'ngLadda'
], function (angular, app, _) {
angular.element(document).ready(function () {
angular.bootstrap(document, ['App']);
document.getElementsByTagName('html')[0].dataset.ngApp = 'App';
});
});
Here is the ladda directive:
/**!
* AngularJS Ladda directive
* #author Chungsub Kim <subicura#subicura.com>
*/
/* global Ladda */
(function () {
'use strict';
angular.module('angular-ladda', []).directive(
'ladda',
[
'$compile',
function ($compile) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.addClass('ladda-button');
if(angular.isUndefined(element.attr('data-style'))) {
element.attr('data-style', 'zoom-in');
}
var ladda = Ladda.create( element[0] ); //here is were Ladda is not defined
$compile(angular.element(element.children()[0]).contents())(scope);
scope.$watch(attrs.ladda, function(loading) {
if(loading || angular.isNumber(loading)) {
if(!ladda.isLoading()) {
ladda.start();
}
if(angular.isNumber(loading)) {
ladda.setProgress(loading);
}
} else {
ladda.stop();
}
});
}
};
}
]
);
})();
In the directive code (line 22, where commented) there is an erroe "Ladda is not defined".
If I will add the following line:
var Ladda = require('ladda');
It all will work, so why the dependency in the main.js not doing this already?
Can you please help me with this one?

I think for the dependency to work, you'd have to define ngLadda declaration as a module
define(function (require) {
// your ngLadda declaration here
}
Edit: there is another possibility
When you look at code of Ladda:
https://github.com/hakimel/Ladda/blob/master/js/ladda.js
You see that Ladda is being wrapped in define(){}
// AMD module
else if( typeof define === 'function' && define.amd ) {
define( [ 'spin' ], factory );
}
In requireJS docs it's stated that:
Only use other "shim" modules as dependencies for shimmed scripts, or AMD libraries that have no dependencies and call define() after they also create a global (like jQuery or lodash). Otherwise, if you use an AMD module as a dependency for a shim config module, after a build, that AMD module may not be evaluated until after the shimmed code in the build executes, and an error will occur. The ultimate fix is to upgrade all the shimmed code to have optional AMD define() calls.
http://requirejs.org/docs/api.html#config-shim
So, Ladda is an AMD module with deps already defined. In your main.js put it outside of shim:
'ladda': {
exports: 'Ladda'
},
'ngLadda': {
deps: ['ladda']
}
shim: {
//your other shimmed modules
}
Put your ngLadda in define(function(require){}) like it's said in original answer, but don't put any dependencies inside.

Related

require.js shim for lib jquery, marionette, backbone, underscore

I used to link libraries :
shim: {
backbone: {
deps: ["jquery", "underscore"],
exports: "Backbone"
},
marionette: {
deps: ["backbone"],
exports: "Marionette"
},
angular: {
exports: "angular"
}
}
but now I have read that these libs uses AMD and shim property is not required! Is it?
main.js
paths: {
marionette: "backbone.marionette"
}
some.js
define( "util",
['marionette'],
function(Marionette){
//test arguments!
//console.log($)
//console.log(jQuery)
//console.log(Backbone)
//console.log(_)
console.log(Marionette) //exist!
}
);
If the third party scripts are not AMD compatible you have to use shims.
You might check if the scripts are AMD compatible if at the top the code does have something like this:
(function(root, factory) {
// Set up Backbone appropriately for the environment. Start with AMD.
if (typeof define === 'function' && define.amd) {
define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
// Export global even in AMD case in case this script is loaded with
// others that may still expect a global Backbone.
root.Backbone = factory(root, exports, _, $);
});
// Next for Node.js or CommonJS. jQuery may not be needed as a module.
} else if (typeof exports !== 'undefined') {
var _ = require('underscore'), $;
try { $ = require('jquery'); } catch(e) {}
factory(root, exports, _, $);
// Finally, as a browser global.
} else {
root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));
}
}(this, function(root, Backbone, _, $) {
// ....
}
And here is how look like for example the configuration file on one of my project:
shim: {
// jQuery Mobile
"jquerymobile": ["jquery"],
// Twitter Bootstrap jQuery plugins
"bootstrap": ["jquery"],
// jQueryUI
"jqueryui": ["jquery"],
// jQuery Cookie
"jquery.cookie": {
deps: ["jquery"],
exports: "jquery.cookie"
},
// jQuery easing functions
"jquery.easing" : {
deps: ["jquery"],
exports: "jquery.easing"
},
// Shim backbone to resolve conflicts on minification
"backbone": {
deps: ['underscore', 'jquery'],
init: function(_, $) {
return this.Backbone = Backbone.noConflict();
}
},
// Backbone.validateAll plugin that depends on Backbone
"backbone.validateAll": ["backbone"],
"backbone.paginator" : {
deps: ["backbone"],
exports : "Backbone.Paginator"
},
"backgrid" : {
deps : ['jquery', 'underscore', 'backbone'],
exports: "Backgrid"
},
"backgrid.paginator" : {
deps: ["backbone", "backgrid"],
exports : "Backgrid.Paginator"
}
}

RequireJS + Backbone without jQuery?

I'm trying to use RequireJS, here is my config file :
require.config({
baseUrl: "/scripts",
paths: {
zepto: "zepto.min",
underscore: "underscore.min",
backbone: "backbone.min"
},
shim: {
zepto: {
exports: "$"
},
underscore: {
exports: "_"
},
backbone: {
deps: ["underscore", "zepto"],
exports: "Backbone"
}
}
});
And this is my app.js :
require(['backbone'], function(Backbone) {
console.log('loaded!');
});
This works fine, but I don't know why RequireJS is trying to load jQuery.
Because Backbone requires module called jquery (look at top of backbone.js) file.
// Set up Backbone appropriately for the environment. Start with AMD.
if (typeof define === 'function' && define.amd) {
define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
// Export global even in AMD case in case this script is loaded with
// others that may still expect a global Backbone.
root.Backbone = factory(root, exports, _, $);
});
and You haven't defined this module.
To hack this use zepto as jquery:
require.config({
baseUrl: "/scripts",
paths: {
jquery: "zepto.min",
underscore: "underscore.min",
backbone: "backbone.min"
},
shim: {
jquery: {
exports: "$"
},
underscore: {
exports: "_"
}
}
});
And second: shim only works with non-amd modules. Backbone is AMD module.

The jquery.fileupload plugin causes require.js to randomly fail imports

I'm using require.js and have a page with an from that used jquery.fileupload. After introducing the plugin I now see some files fail to be imported before the define call back is executed. This causes random errors where the libraries can't find their dependencies. It's as though require.js is moving on before all the dependencies can be resolved.
I've followed these instructions:
https://github.com/blueimp/jQuery-File-Upload/wiki/How-to-use-jQuery-File-Upload-with-RequireJS
But beyond that it's a very vanilla install. I'm using the minified versions of libraries where possible. Any insight is welcome.
here's the main.js:
(function () {
'use strict';
require.config({
baseUrl: '/js',
waitSeconds: 800,
paths: {
jquery: ['//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min',
'lib/jquery/jquery-2.0.3.min'],
'jquery.fileupload': 'lib/jquery.fileupload/jquery.fileupload',
'jquery.fileupload-ui': 'lib/jquery.fileupload/jquery.fileupload-ui',
'jquery.fileupload-image': 'lib/jquery.fileupload/jquery.fileupload-image',
'jquery.fileupload-validate': 'lib/jquery.fileupload/jquery.fileupload-validate',
'jquery.fileupload-video': 'lib/jquery.fileupload/jquery.fileupload-video',
'jquery.fileupload-audio': 'lib/jquery.fileupload/jquery.fileupload-audio',
'jquery.fileupload-process': 'lib/jquery.fileupload/jquery.fileupload-process',
'jquery.ui.widget': 'lib/jquery.ui/jquery.ui.widget',
'jquery.iframe-transport': 'lib/jquery.iframe-transport/jquery.iframe-transport',
'load-image': 'lib/load-image/load-image.min',
'load-image-meta': 'lib/load-image/load-image-meta',
'load-image-exif': 'lib/load-image/load-image-exif',
'load-image-ios': 'lib/load-image/load-image-ios',
'canvas-to-blob': 'lib/canvas-to-blob/canvas-to-blob.min',
tmpl: 'lib/tmpl/tmpl.min',
bootstrap: 'lib/bootstrap/bootstrap',
bootstrapTab: 'lib/bootstrap/bootstrap-tab',
EventEmitter: 'lib/event_emitter/EventEmitter',
linkedin: ['//platform.linkedin.com/in.js?async=true',
'http://platform.linkedin.com/in.js?async=true'],
skinny: 'lib/skinny/skinny',
selectize: 'lib/selectize/selectize.min',
sifter: 'lib/sifter/sifter',
microplugin: 'lib/microplugin/microplugin.min'
},
shim: {
bootstrap: {
deps: ['jquery'],
},
bootstrapTab: {
deps: ['jquery', 'bootstrap'],
},
linkedin: {
exports: 'IN'
},
selectize: {
deps: ['jquery', 'sifter', 'microplugin']
},
'jquery.iframe-transport': {
deps: ['jquery']
}
}
});
require(['app'], function (App) {
App.initialize();
});
}());
And the from code:
define([], function () {
'use strict';
return function () {
require(['jquery', 'tmpl', 'load-image', 'canvas-to-blob',
'jquery.iframe-transport', 'jquery.fileupload-ui'], function ($) {
$('#product').fileupload({
url: '/products/create'
});
});
};
});
The module gets called after the page has been loaded.
It's also worth noting that all files are downloaded successfully. No 404's, etc.
It turns out there is a flaw in the minified version of load-image.js that breaks how the dependencies load. I don't have exact proof as to why, it could be the smaller size causes a race condition, or it could be something weird in that particular file. What I do know is the minified version causes the random errors and the normal version does not (this is off master so I suppose I was taking a risk).
I raised a flag here
EDIT: it turns out the minified version of the plugin includes all the extensions which explains the odd dependency behavior.
The Answer from matt is the best solution in this case. Thanks a million, it save us a lot of time.
In requirejs.config, you have to add the load-image dependecies separatly - file by file.
For example:
require.config({
'jquery.ui.widget' : 'lib/jQuery-File-Upload-9.9.2/js/vendor/jquery.ui.widget',
'jquery.fileupload':'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload',
'jquery.fileupload-ui': 'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-ui',
'jquery.fileupload-image': 'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-image',
'jquery.fileupload-validate':'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-validate',
'jquery.fileupload-audio':'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-audio',
'jquery.fileupload-video':'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-video',
'jquery.fileupload-process': 'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-process',
'jquery.fileupload-jquery-ui': 'lib/jQuery-File-Upload-9.9.2/js/jquery.fileupload-jquery-ui',
'jquery.iframe-transport': 'lib/jQuery-File-Upload-9.9.2/js/jquery.iframe-transport',
'load-image':'lib/load-image-1.10.0',
'load-image-meta':'lib/load-image-meta-1.10.0',
'load-image-ios':'lib/load-image-ios-1.10.0',
'load-image-exif':'lib/load-image-exif-1.10.0',
'canvas-to-blob':'lib/canvas-to-blob-2.0.5',
'tmpl':'lib/tmpl.2.4.1'
}
});
call in html site:
requirejs(['jquery',
'jquery.ui.widget',
'tmpl',
'load-image',
'jquery.iframe-transport',
'jquery.fileupload-ui'], function () {
$('#fileupload').fileupload({
url: 'photo-upload.html'
});
}
);
One possibility modify the shim:
shim: {
bootstrap: {
deps: ['jquery'],
},
bootstrapTab: {
deps: ['jquery', 'bootstrap'],
},
linkedin: {
exports: 'IN'
},
selectize: {
deps: ['jquery', 'sifter', 'microplugin']
},
'jquery.iframe-transport': {
deps: ['jquery']
},
'jquery.fileupload-ui':{
deps: ['jquery']
}
Another option downgrade jquery to 1.X (this is because the sample page is using jquery 1.X)

Getting blank page using RequireJS and Grunt

I'm going a bit crazy here. I'm trying to use Grunt to go through a large RequireJS-based project and combine and minify the results during the deployment process. Here is my grunt process (using grunt-contrib-requirejs):
requirejs: {
compile: {
options: {
baseUrl: "public/js",
mainConfigFile: "public/js/config.js",
name: 'config',
out: "public/js/optimized/script.min.js",
preserveLicenseComments: false
}
}
}
Initially, I was taking the outputted script and placing it in the HTML -- but this lead to the 'define is undefined' error that means that RequireJS wasn't evoked. So instead, I'm putting in the HTML like this:
<script data-main="js/optimized/script.min" src="js/vendor/require.js"></script>
However, now I'm only getting a blank page.
The closest thing I can find out there that sounds like this is here, but's not being super helpful right now. For reference, I was using this as a starting point of my project -- however, when I run it, everything seems to be working for them but I can't find the differences.
Here is my config.js file:
require.config({
//Define the base url where our javascript files live
baseUrl: "js",
//Increase the timeout time so if the server is insanely slow the client won't burst
waitSeconds: 200,
//Set up paths to our libraries and plugins
paths: {
'jquery': 'vendor/jquery-2.0.3.min',
'underscore': 'vendor/underscore.min',
'backbone': 'vendor/backbone.min',
'marionette': 'vendor/backbone.marionette',
'mustache': 'vendor/mustache.min',
'bootstrap': 'vendor/bootstrap.min',
'bootbox': 'vendor/bootbox.min',
'jquery-ui': 'vendor/jquery-ui-1.10.2',
'app-ajax': '../conf/app-ajax',
'common': 'common',
'moment': 'vendor/moment.min'
},
//Set up shims for non-AMD style libaries
shim: {
'underscore': {
exports: '_'
},
'backbone': {
deps: ['underscore', 'jquery'],
exports: 'Backbone'
},
'marionette': {
deps: ['backbone', 'underscore', 'jquery'],
exports: 'Marionette'
},
'mustache': {
exports: 'mustache'
},
'bootstrap': {
deps: ['jquery']
},
'bootbox': {
deps: ['jquery', 'bootstrap'],
exports: 'bootbox'
},
'jquery-ui': {
deps: ['jquery']
},
'jquery-layout': {
deps: ['jquery', 'jquery-ui']
}
}
});
//Initalize the App right after setting up the configuration
define([
'jquery',
'backbone',
'marionette',
'common',
'mustache',
'bootbox',
'controllers/GlobalController',
'routers/GlobalRouter'
],
function ($, Backbone, Marionette, Common, Mustache, bootbox) {
//Declare ECMAScript5 Strict Mode first and foremost
'use strict';
//Define the App Namespace before anything else
var App = Common.app_namespace || {};
//Create the Marionette Application
App.Application = new Marionette.Application();
//Add wrapper region, so we can easily swap all of our views in the controller in and out of this constant
App.Application.addRegions({
wrapper: '#wrapper'
});
// Set up Initalizer (this will run as soon as the app is started)
App.Application.addInitializer(function () {
//Reach into Marionette and switch out templating system to Mustache
Backbone.Marionette.TemplateCache.prototype.compileTemplate = function (rawTemplate) {
return Mustache.compile(rawTemplate);
};
var globalController = new App.Controllers.GlobalController();
var globalRouter = new App.Routers.GlobalRouter({
controller: globalController
});
//Start Backbone History
Backbone.history.start();
});
//Start Application
App.Application.start();
}
);
Okay, so this is the crazy simple fix:
In the module that's declared after the require.config, use 'require' instead of 'define' when declaring the module.
If you use 'define', it added 'config' as a dependency of that module, which broke the whole thing. Craziness!

Underscore.string with RequireJS

I'm trying to use both Underscore and Underscore.string with RequireJS.
Contents of main.js:
require.config({
paths: {
'underscore': '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
'underscore-string': '//cdnjs.cloudflare.com/ajax/libs/underscore.string/2.3.0/underscore.string.min',
},
shim: {
'underscore': {
exports: '_'
},
'underscore-string': {
deps: ['underscore'],
exports: '_s'
},
}
});
var modules = ['underscore-string'];
require(modules, function() {
// --
});
Browser sees the _, but doesn't see the _s - it is undefined.
Ideally i want to have Underscore under _ and Underscore.string under _.str, but _ and _s are fine too. How can i do that?
Versions: RequireJS 2.1.5, Underscore 1.4.4, Underscore.string 2.3.0
Note: Thanks to #jgillich make sure, that paths have two slashes (//cdnjs.cloudfare.com/...), otherwise the browser would think that URL is relative to the server, and Firebug will throw:
Error: Script error
http://requirejs.org/docs/errors.html#scripterror
I found the error. For some reason RequireJS doesn't work with version of Underscore.string from cdnjs.com, so i replaced it with Github version. I guess it has something to do with the commit 9df4736.
Currently my code looks like the following:
require.config({
paths: {
'underscore': '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
'underscore-string': '//raw.github.com/epeli/underscore.string/master/dist/underscore.string.min',
},
shim: {
'underscore': {
exports: '_'
},
'underscore-string': {
deps: ['underscore'],
},
}
});
var modules = ['underscore', 'underscore-string'];
require(modules, function(_) {
// --
});
Underscore.string resides in _.str.
Edit: As of 16 July 2013 the CDNJS version is updated with the upstream.
Battling with this for hours before i understand what i was doing wrong
This is what i did wrong
You should not rename the file underscore.string in main.js
even though in my library i did rename the file in paths i name it back to 'underscore.string'
This is how your main.js should look like
require.config({
paths: {
underscore: 'lib/underscore',
'underscore.string' : 'lib/_string' ,
},
shim: {
underscore: {
exports: '_',
deps: [ 'jquery', 'jqueryui' ]
},
'underscore.string': {
deps: [ 'underscore' ]
},
}
....
You could then either add it as dependency with in your shim like i did for my mixin file
shim: {
mixin : {
deps: [ 'jquery', 'underscore', 'underscore.string' , 'bootstrap' ]
},
Or just define it in your different pages like
/*global define */
define([
'underscore.string'
], function ( ) {
it just work now you can access it through _.str or _.string
This is why you should do it this way and not try to name it something else
on line 663 of underscore.string.js
// Register as a named module with AMD.
if (typeof define === 'function' && define.amd)
define('underscore.string', [], function(){ return _s; });
Which means that it will only register it with AMD require JS if you are defining 'underscore.string'
works for my ONLY if I use exact "underscore.string" module name in shim. Seems related to hardcoded name in underscore.string itself
Exempt from underscore.string source code (this branch is executed when require used):
// Register as a named module with AMD.
if (typeof define === 'function' && define.amd)
define('underscore.string', [], function(){ return _s; });
So for me the only working configuration is:
require.config({
paths: {
'underscore': '//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min',
'underscore.string': '//raw.github.com/epeli/underscore.string/master/dist/underscore.string.min',
},
shim: {
'underscore': {
exports: '_'
},
'underscore.string': {
deps: ['underscore'],
},
}
});
var modules = ['underscore', 'underscore.string'];
require(modules, function(_) {
// --
});
Here's a working code using Requirejs "order" plugin, also includes Jquery, and everything loads without any conflict:
requirejs.config({
baseUrl: "assets",
paths: {
order: '//requirejs.org/docs/release/1.0.5/minified/order',
jquery: 'http://code.jquery.com/jquery-2.1.0.min',
underscore: '//underscorejs.org/underscore-min',
underscorestring: '//raw.githubusercontent.com/epeli/underscore.string/master/dist/underscore.string.min',
underscoremixed: 'js/underscore.mixed' // Create separate file
},
shim: {
underscore: { exports: '_' },
underscorestring: { deps: ['underscore'] }
}
});
require(['order!jquery','order!underscoremixed'], function($,_) {
// test
console.log( _.capitalize('capitalized text') );
});
Inside js/underscore.mixed.js put the following...
define(['underscore','underscorestring'], function() {
_.mixin(_.str.exports());
return _;
});
Cheers! :)

Categories