Injecting modules into AngularJS - javascript

I'm trying to inject a third party file uploader into my Angular App. I had it working fine but took a break from the project and revisiting it now I've decided to use requireJS, and am having a terrible time trying to inject this module in. I'm sure it's just semantics as to how to get it to actually work but I'm not exactly sure what I am doing wrong.
File: main.js
Loading the uploader here and giving angular as the dependancy.
require.config({
paths: {
angular: '../bower_components/angular/angular.min',
angularRoute: '../bower_components/angular-route/angular-route.min',
angularFileUpload: 'modules/file-upload/angular-file-upload',
jquery: '//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min',
fastclick: '//cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.0/fastclick.min'
},
shim: {
'angular' : {'exports' : 'angular'},
'angularRoute': ['angular'],
'angularFileUpload': ['angular'],
'jquery': {
exports: '$'
}
},
priority: [
"angular"
]
});
// http://code.angularjs.org/1.2.1/docs/guide/bootstrap#overview_deferred-bootstrap
window.name = "NG_DEFER_BOOTSTRAP!";
require( [
'angular',
'routes',
'jquery',
'fastclick',
'app'
], function(angular, app) {
'use strict';
// Some config stuff here
});
File: app.js
This is where all of the angular modules are loaded into the app, This is mainly where I have been trying to inject the file uploader, in a similar fashion.
define([
'angular',
'filters',
'services',
'directives',
'controllers',
'angularRoute'
], function (angular, filters, services, directives, controllers) {
'use strict';
// Declare app level module which depends on filters, and services
return angular.module('myApp', [
'ngRoute',
'myApp.controllers',
'myApp.filters',
'myApp.services',
'myApp.directives'
]);
});
File: angular-file-upload.js
The module, It looks like it's all setup to fit in with the AMD structure.. here is the top part of the file, the rest of the file is directives and factories like angularFileUpload.directive()
(function(angular, factory) {
if (typeof define === 'function' && define.amd) {
define('angular-file-upload', ['angular'], function(angular) {
return factory(angular);
});
} else {
return factory(angular);
}
}(angular || null, function(angular) {
/**
* The angular file upload module
* #author: nerv
* #version: 0.2.9.6, 2013-12-06
*/
var angularFileUpload = angular.module('angularFileUpload', []);
If anybody could provide any information on how this could be injected I would greatly appreciate it!

Basically, you first need to define the path to the module in your requirejs config:
require.config({
paths: {
"angular" : "relative/path/to/angular",
"angular-file-upload" : "relative/path/to/angular-file-upload",
... other modules
},
shim: {
"angular": {
exports: "angular"
},
// Currently needed (see explanation below)
"angular-file-upload": ["angular"]
}
})
As you can see, I needed to define a shim as well - which should not have been needed since angular-file-upload already is AMD friendly and defines that it relies on angular. That is what you see here:
define('angular-file-upload', ['angular'], function(angular) {
return factory(angular);
});
However, due to what I see as a bug (and which I have described here https://github.com/nervgh/angular-file-upload/issues/171) the angular-file-upload script checks for the existence of angular when loaded - but since angular is not a global variable yet, that fails with an exception (Uncaught ReferenceError: angular is not defined angular-file-upload.js:13) causing the library not to make itself available as a requirejs module.
Anyway, with the shim fix applied, that would not be an issue for now.
Then, before we are all set, in your app.js file - you need to set angular-file-upload as a module dependency and make sure to register the angular module angularFileUpload with you angular app module - and then you should be ready to rock. So something like this should work:
define([
'angular',
'filters',
'services',
'directives',
'controllers',
'angularRoute',
'angular-file-upload'
], function (angular, filters, services, directives, controllers) {
'use strict';
// Declare app level module which depends on filters, and services
return angular.module('myApp', [
'ngRoute',
'myApp.controllers',
'myApp.filters',
'myApp.services',
'myApp.directives',
'angularFileUpload'
]);
});

Related

Angular + Require + Angular-resources and cookies modules lead to "Error: No module: ngResource"

I am not able to use ngResource using require.js I am having exactly same problem as discussed here
Below is my code :
main.js ( data-main attribute of require.js )
// https://groups.google.com/forum/#!topic/angular/I6CSeG0Z2Vo
require.config({
paths: {
'angular': '../bower_components/angular/angular',
'angularResource': '../node_modules/angular-resource/angular-resource'
},
shim:{
'angular':{
exports: 'angular'
},
'angularResource':{
deps: ['angular'],
exports: 'angularResource'
}
}
});
debugger;
require(['controllers/MainCtrl']);
require(['directives/owNavigation']);
require(['directives/owFooter']);
Below is my app.js where I am creating my angular app module.
app.js
define(['angular','angularResource'],function(angular,angularResource){
debugger;
var app = angular.module('app',['ngResource']);
return {
angularModule: app
}
});
But, 'angularResouce' parameter is always null. I can see 'angular' parameter has proper value and I can create my 'app' module without passing 'ngResource' as a dependency.
I am using below version
Angularjs v1.6.6
RequireJS 2.3.5
angular-resource v1.6.6
I can see in chrome developer tool's network tab that requirejs is loading file 'angular-resource.js' but still app.js module is not receiving it as a parameter.
Here is the error that can be seen on console
Delete export from the shim angularResource :
shim:{
'angular':{
exports: 'angular'
},
'angularResource':{
deps: ['angular']
}
}
It should work (working for me), keeping everything else same.

Why my AngularJS + RequireJS application is not building via grunt-contrib-requirejs?

I have src of my application. I use AngularJS. I use RequireJS as module loader. I use Grunt as task runner. When I run application using src: everything is good. When I build application with Grunt, application is not working. I got no errors in console.
Main thing I noticed: my code (code of my application: app.js and files under js/) does not appear in output file which is set in grunt task settings. Also, I don't think there is something about AngularJS.
Main config file:
require.config({
paths: {
'angular' : '../components/angular/angular',
/* etc..... */
'jquery': '../components/jquery/dist/jquery',
'application': './app'
},
shim: {
/* etc */
application: {
deps: ['angular']
},
angular: {
exports : 'angular'
}
},
baseUrl: '/js'
});
require(['application', 'angular', 'ngRoute', 'bootstrap' /* ngRoute and bootstrap from etc :) */], function (app) {
app.init();
});
My app in app.js is:
define([
'require', 'angular', 'main/main', 'common/common'
], function (require) {
'use strict';
var angular = require('angular');
var app = angular.module('myApp', ['ngRoute', 'main', 'common']);
app.init = function () {
angular.bootstrap(document, ['myApp']);
};
app.config(['$routeProvider',
function ($routeProvider) {
$routeProvider
./* ... some code */
}
]);
return app;
});
I add main RequireJS config file at the end of body tag:
<script type="text/javascript" src="components/requirejs/require.js" data-main="js/bootstrap.js"></script>
Now I have problem. I have Grunt as build system. I have this task:
grunt.initConfig({
requirejs: {
compile: {
options: {
baseUrl: "public/js",
mainConfigFile: "public/js/bootstrap.js",
name: 'bootstrap',
out: "build/js/bootstrap.js",
optimize: 'none'
}
}
},
// etc
I have no optimisation, so I get ~11k lines of code in output file.
As I said. Main problem is: no AngularJS code and no application code in output file.
Why? I set up mainConfigFile correctly. Problem is in RequireJS config file? But everything is okay, when I am running my app on src.
It would be better if you can provide the exactly error output you get. And where you got it (from browser's console or from terminal during build process)
For now I will suggest some adjustments what could possibly help with your case.
angular: {
exports : 'angular'
}
Here you have already export angular.js into global local variable (inside every require and define block).
And by doing var angular = require('angular'); you are possibly asynchronously override angular variable inside your app.js module.
For 'require' being added into define block, as r.js always reading what module got to be loaded in very first step, and then merged into single file. And this may confuse r.js to merging requireJS into itself.
Suggest this adjustment for your app.js:
define([ // Removed 'require' because no needed , it is already global and usable anywhere
'angular', 'main/main', 'common/common'
], function () {
'use strict';
// var angular = require('angular'); // This is a very common mistake. You are not going to call angular this way, requireJS difference with commonJS.
var app = angular.module('myApp', ['ngRoute', 'main', 'common']);
app.init = function () {
angular.bootstrap(document, ['myApp']);
};
app.config(['$routeProvider',
function ($routeProvider) {
$routeProvider
./* ... some code */
}
]);
return app;
});
And last but not least data-main="js/bootstrap.js" I think it should be js/main.js or a typo.
EDIT added explanations for 'require' in define block, and angular local variable.

angular.js loaded instead of angular.min.js with requirejs

I'm using Webjars to import AngularJS into my web project.
For some reason the minified version of AngularJS won't be served even though I'm referencing those in my main. I was expecting to see angular.min.js and angular-route.min.js being loaded, but I'm seeing the regular angular.js and angular-route.js. What am I doing wrong here?
My main.js:
'use strict';
requirejs.config({
paths: {
'angular': '../lib/angularjs/angular.min',
'angular-route': '../lib/angularjs/angular-route.min',
'async': '../lib/requirejs-plugins/src/async'
},
shim: {
'angular': {
exports : 'angular'
},
'angular-route': {
deps: ['angular'],
exports : 'angular'
}
}
});
require(['angular', './controllers', './directives', './filters', './services', 'angular-route','./places-autocomplete','async','./gmaps'],
function(angular, controllers) {
initialize();
// Declare app level module which depends on filters, and services
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ngRoute']).
config(['$routeProvider', function($routeProvider) {
....
}]);
angular.bootstrap(document, ['myApp']);
});
My html loads requirejs like this:
<script>
#Html(org.webjars.RequireJS.getSetupJavaScript(routes.WebJarAssets.at("").url))
</script>
<script data-main="#routes.Assets.versioned("javascripts/main.js")"
src="#routes.WebJarAssets.at(WebJarAssets.locate("require.min.js"))"></script>
and the above requirejs.config snippet resides in main.js
I looked into the sources of requirejs. Here's what I found:
requirejs splits each path, you defined in the config object, into its components (i.e. the directories, the filename and the extension). For some reason (node module naming conventions) the last extension is dropped. They do not check if that's a '.js'. Then this path array is used to access a module. Without a plugin rquirejs only handles .js files. It adds a .js if nessecary.
Now you can see what happens in your example. In the first step requirejs drops the .min extension. When it loads the module it joins the path components and adds a .js to the end. Then it loads the full module and not the minified version.
If you add a .js to your paths, then this .js was dropped and the .min is still there.
Try to add
enforceDefine: true,

RequireJS + Angular: Undefined app. Callback doesn't shoot

I got main.js with this simple code:
'use strickt';
require.config({
paths: {
'angular' : 'libs/angular' ,
'angular-router' : 'libs/angular-route' ,
},
shim : {
'angular' : {
exports : 'angular'
},
'angular-router' : {
deps: ['angular']
}
}
});
require(['app'], function (mainApp) {
console.log(mainApp);
});
As you can see, I try to fetch app inside require callback. But all I got its undefined.
Here what I got inside app.js file:
define('mainApp', ['angular', 'angular-route'], function (angular) {
var app = angular.module('mainApp', ['ngRoute']);
console.log('should be fired from app.js');
return app;
});
So the question:
Function argument 'mainApp' as undefined inside main.js callback seems logical because console.log() inside app.js doesnt shoot. Can somebody tell me what is wrong with it?
Just remove module name in app.js file (or change it to 'app'). You app.js file will look like:
define(['angular', 'angular-route'], function (angular) {
var app = angular.module('mainApp', ['ngRoute']);
console.log('should be fired from app.js');
return app;
});
http://requirejs.org/docs/api.html#modulename
You can explicitly name modules yourself, but it makes the modules
less portable -- if you move the file to another directory you will
need to change the name. It is normally best to avoid coding in a name
for the module and just let the optimization tool burn in the module
names. The optimization tool needs to add the names so that more than
one module can be bundled in a file, to allow for faster loading in
the browser.

Loading Backbone and Underscore using RequireJS

I'm trying to load Backbone and Underscore (as well as jQuery) with RequireJS. With the latest versions of Backbone and Underscore, it seems kind of tricky. For one, Underscore automatically registers itself as a module, but Backbone assumes Underscore is available globally. I should also note that Backbone doesn't seem to register itself as a module which makes it kind of inconsistent with the other libs. This is the best main.js I could come up with that works:
require(
{
paths: {
'backbone': 'libs/backbone/backbone-require',
'templates': '../templates'
}
},
[
// jQuery registers itself as a module.
'http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js',
// Underscore registers itself as a module.
'http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.2.1/underscore-min.js'
], function() {
// These nested require() calls are just due to how Backbone is built. Underscore basically says if require()
// is available then it will automatically register an "underscore" module, but it won't register underscore
// as a global "_". However, Backbone expects Underscore to be a global variable. To make this work, we require
// the Underscore module after it's been defined from within Underscore and set it as a global variable for
// Backbone's sake. Hopefully Backbone will soon be able to use the Underscore module directly instead of
// assuming it's global.
require(['underscore'], function(_) {
window._ = _;
});
require([
'order!http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.5.3/backbone-min.js',
'order!app'
], function(a, app) {
app.initialize();
})
});
I should mention that, while it works, the optimizer chokes on it. I receive the following:
Tracing dependencies for: main
js: "/home/httpd/aahardy/requirejs/r.js", line 7619: exception from uncaught JavaScript throw: Error: Error: Error evaluating module "undefined" at location "/home/httpd/aahardy/phoenix/trunk/ui/js/../../ui-build/js/underscore.js":
JavaException: java.io.FileNotFoundException: /home/httpd/aahardy/phoenix/trunk/ui/js/../../ui-build/js/underscore.js (No such file or directory)
fileName:/home/httpd/aahardy/phoenix/trunk/ui/js/../../ui-build/js/underscore.js
lineNumber: undefined
http://requirejs.org/docs/errors.html#defineerror
In module tree:
main
Is there a better way of handling this? Thanks!
RequireJS 2.X now organically addresses non-AMD modules such as Backbone & Underscore much better, using the new shim configuration.
The shim configuration is simple to use: (1) one states the dependencies (deps), if any, (which may be from the paths configuration, or may be valid paths themselves). (2) (optionally) specify the global variable name from the file you're shimming, which should be exported to your module functions that require it. (If you don't specify the exports, then you'll need to just use the global, as nothing will get passed into your require/define functions.)
Here is a simple example usage of shim to load Backbone. It also adds an export for underscore, even though it doesn't have any dependencies.
require.config({
shim: {
underscore: {
exports: '_'
},
backbone: {
deps: ["underscore", "jquery"],
exports: "Backbone"
}
}
});
//the "main" function to bootstrap your code
require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone) { // or, you could use these deps in a separate module using define
});
Note: this simplified code assumes that jquery, backbone and underscore are in files named "jquery.js", "backbone.js" and "underscore.js" in the same directory as this "main" code (which becomes the baseURL for require). If this isn't the case, you'll need to use a paths config.
I personally think with the built-in shim functionality, the advantages of not using a forked version of Backbone & Underscore outweigh the benefits of using the AMD fork recommended in the other popular answer, but either way works.
Update: As of version 1.3.0 Underscore removed AMD (RequireJS) support.
You can use the amdjs/Backbone 0.9.1 and the amdjs/Underscore 1.3.1 fork with AMD support from James Burke (the maintainer of RequireJS).
More info about AMD support for Underscore and Backbone.
// main.js using RequireJS 1.0.7
require.config({
paths: {
'jquery': 'libs/jquery/1.7.1/jquery',
'underscore': 'libs/underscore/1.3.1-amdjs/underscore', // AMD support
'backbone': 'libs/backbone/0.9.1-amdjs/backbone', // AMD support
'templates': '../templates'
}
});
require([
'domReady', // optional, using RequireJS domReady plugin
'app'
], function(domReady, app){
domReady(function () {
app.initialize();
});
});
The modules are properly registered and there is no need for the order plugin:
// app.js
define([
'jquery',
'underscore',
'backbone'
], function($, _, Backbone){
return {
initialize: function(){
// you can use $, _ or Backbone here
}
};
});
Underscore is actually optional, because Backbone now gets its dependencies on its own:
// app.js
define(['jquery', 'backbone'], function($, Backbone){
return {
initialize: function(){
// you can use $ and Backbone here with
// dependencies loaded i.e. Underscore
}
};
});
With some AMD sugar you could also write it like this:
define(function(require) {
var Backbone = require('backbone'),
$ = require('jquery');
return {
initialize: function(){
// you can use $ and Backbone here with
// dependencies loaded i.e. Underscore
}
};
});
Regarding the optimizer error: doublecheck your build configuration. I assume your path configuration is off. If you have a directory setup similar to the RequireJS Docs you can use:
// app.build.js
({
appDir: "../",
baseUrl: "js",
dir: "../../ui-build",
paths: {
'jquery': 'libs/jquery/1.7.1/jquery',
'underscore': 'libs/underscore/1.3.1-amdjs/underscore',
'backbone': 'libs/backbone/0.9.1-amdjs/backbone',
'templates': '../templates'
},
modules: [
{
name: "main"
}
]
})
For reference, as of version 1.1.1 (~Feb '13), Backbone also registers itself as an AMD module. It will work with requirejs without the need to use its shim config. (James Burke's amdjs fork also hasn't been updated since 1.1.0)
Good news, Underscore 1.6.0 now supports requirejs define !!!
versions below this require shims, or requiring underscore.js then blindly hoping that the "_" global variable hasn;t been smashed (which to be fair is a fair bet)
simply load it in by
requirejs.config({
paths: {
"underscore": "PATH/underscore-1.6.0.min",
}
});
I will write down directly, you can read the explaination on requirejs.org, you could use below code as a snippet for your everyday use; (p.s. i use yeoman) (since many things updated, im posting this as of Feb 2014.)
Make sure you included script in your index.html
<!-- build:js({app,.tmp}) scripts/main.js -->
<script data-main="scripts/main" src="bower_components/requirejs/require.js"></script>
<!-- endbuild -->
Then, in main.js
require.config({
shim: {
'backbone': {
deps: ['../bower_components/underscore/underscore.js', 'jquery'],
exports: 'Backbone'
}
},
paths: {
jquery: '../bower_components/jquery/jquery',
backbone: '../bower_components/backbone/backbone'
}
});
require(['views/app'], function(AppView){
new AppView();
});
app.js
/**
* App View
*/
define(['backbone', 'router'], function(Backbone, MainRouter) {
var AppView = Backbone.View.extend({
el: 'body',
initialize: function() {
App.Router = new MainRouter();
Backbone.history.start();
}
});
return AppView;
});
I hope I was useful.!
require.config({
waitSeconds: 500,
paths: {
jquery: "libs/jquery/jquery",
jqueryCookie: "libs/jquery/jquery.cookie",
.....
},
shim: {
jqxcore: {
export: "$",
deps: ["jquery"]
},
jqxbuttons: {
export: "$",
deps: ["jquery", "jqxcore"]
}
............
}
});
require([
<i> // Load our app module and pass it to our definition function</i>
"app"
], function(App) {
// The "app" dependency is passed in as "App"
// Again, the other dependencies passed in are not "AMD" therefore don't pass a parameter to this function
App.initialize();
});

Categories

Resources