I'v just generated an angular application using Yeoman project generator tool. Generated project has a directory "node_modules". Inside this module are a lot of maybe "predefined functions" for array-diff etc.., and i want to use those functions inside my angularJS application(controllers, directives) only if it's possible.
I'v tried to use those node_modules using RequireJS and Node-Browserfy unfortonatelly without any success everytime i got some error . Example "filter is not defiend etc...". Is there any Step by Step tutorial to do this module integration into an AngularJS application?
My project structure is:
This is my bundle.js generated by node-browswerfy
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var myFilter =require('../../node_modules/array-filter/index.js');
},{"../../node_modules/array-filter/index.js":2}],2:[function(require,module,exports){
/**
* Array#filter.
*
* #param {Array} arr
* #param {Function} fn
* #return {Array}
*/
module.exports = function (arr, fn) {
if (arr.filter) return arr.filter(fn);
var ret = [];
for (var i = 0; i < arr.length; i++) {
if (!hasOwn.call(arr, i)) continue;
if (fn(arr[i], i, arr)) ret.push(arr[i]);
}
return ret;
};
var hasOwn = Object.prototype.hasOwnProperty;
},{}]},{},[1]);
This is my controller
'use strict';
/**
* #ngdoc function
* #name alam2App.controller:MainCtrl
* #description
* # MainCtrl
* Controller of the alam2App
*/
angular.module('alam2App')
.controller('MainCtrl', function ($scope) {
var array = [1, 2, 3];
console.log(myFilter (array, function (el, i, arr) {
return false; // I throw it on the ground!
}));
$scope.awesomeThings = [
'HTML5 Boilerplate',
'AngularJS',
'Karma'
];
});
Error message i got on console
ReferenceError: myFilter is not defined
Documentation is always a good place to start, requirejs is well documented and their page referencing the use of node and node_modules describes exactly what you need to do.
r.js creates a deployable bundle of all the code you are using and it doesnt much matter which folder you place it in. r.js will bundle all your code into one file, you simple include this in your page and it executes containing all the dependencies you require.
Angular made a poor choice regarding module definition, it wasnt such a terrible choice at the time, just a short-sighted one, so you are stuck with having to shoe-horn in solutions to problems like this. Fortunately the community is fantastic and have come up with multiple solutions. Try searching for ways to combine commonJS modules and AMD modules, or, look for AMD-compliant alternatives to whichever modules you want as dependencies.
Related
My use case is: we have several helper classes, A and B, that are services, A depends on B, and I wanted to make them providers so that they can be used in .config phase.
I followed this SO answer to load a provider inside a provider.
As you can see here, it works:
http://plnkr.co/edit/SIvujHt7bprFumhxwJqD?p=preview
var coreModule = angular.module('CoreModule', []);
coreModule.provider('Car', function() {
//CarProvider.engine
this.engine = 'big engine';
//Car
this.$get = function() {
return {
color: 'red'
};
};
});
coreModule.provider('ParameterService', ['$injector', function($injector) {
try {
var CarProvider = $injector.get('CarProvider');
this.deepEngine = CarProvider.engine;
console.log('deepEngine = ' + this.deepEngine);
} catch (e) {
console.log("nope!")
}
// ParameterService
this.$get = function() {
return {};
};
}]);
coreModule.config(function(CarProvider) {
console.log('configEngine = ' + CarProvider.engine); // big engine
});
This works if I have Car and ParameterService in one file in this order.
However when I split Car and ParameterService into multiple files on disk, or I define ParameterService before Car in the same file, $injector.get('CarProvider') inside ParameterService fails.
How do I fix the issue?
I want to have one provider/service per file and I don't understand what is missing.
The order in which the services are defined doesn't matter during run phase, where service instances are injected. But it does matter during configuration phase, where service providers are injected, i.e. in provider constructors and config blocks.
Providers and config blocks are executed in the order in which they are defined. If Car provider is defined after ParameterService provider or config block, CarProvider doesn't exist at the moment when those two are executed.
To avoid potential race conditions, one module per file pattern should be followed. This allows to keep the app highly modular (also beneficial for testing) and never care about the order in which the files are loaded. E.g.:
angular.module('app', ['app.carService', 'app.parameterService']).config(...);
angular.module('app.carService', []).provider('Car', ...);
angular.module('app.parameterService', []).provider('ParameterService', ...);
Module parts are executed in the order in which the modules are defined in angular.module array hierarchy, from children to parents.
The decision if config block needs its own module depends on what it does (mostly for testing reasons).
It is possible to have providers in different files. You just need to attach them to the first module that you created.
If your markup looks like this:
<script src="coreModule.js"></script>
<script src="parameterService.js"></script>
Then, in coreModule.js, define your module:
angular.module('CoreModule', [])
.provider('Car', function() {
...
}
Remember, the second parameter ([]) tells angular to create a new module.
Then, declare your other provider in a different file, and attach it to your existing 'CoreModule' module:
angular.module('CoreModule')
.provider('ParameterService', ['$injector', function($injector) {
...
}
Notice that we are only passing one parameter to .module(). This tells angular to add your provider to an existing module.
Plunkr Demo
I have the gulp task set up and running to create an Angular app, and it runs without error and creates the files correctly, but when I load the page on a browser, I get following error messages.
Is there some step or some plugin I'm missing to get the Angular files to all "work"? I've used the angularFilesort() and ngAnnotate() plugins already.
var bower = gulp.src(bower_files)
.pipe(concat("bower-expanded.js"))
.pipe(gulp.dest(paths.prod))
.pipe(rename("bower.js"))
.pipe(uglify())
.pipe(gulp.dest(paths.prod + paths.js));
// gather and compress the app's js files
var app = gulp.src(paths.source + "app/**/*.js")
.pipe(angularFilesort())
.pipe(concat("app-expanded.js"))
.pipe(ngAnnotate({
add: true,
single_quotes: true
}))
.pipe(gulp.dest(paths.prod))
.pipe(rename("app.js"))
.pipe(uglify())
.pipe(gulp.dest(paths.prod + paths.js));
The errors are
TypeError: (intermediate value)(...) is not a function
(function(angular) {
which points to these lines of code
(function(angular) {
'use strict';
/**
* Called with an array this acts like map, otherwise it acts like _.mapValues
* in lodash.
* #return {Array|Object} The same type as the input argument.
*/
var mapValues = function(obj, callback) {
if (angular.isArray(obj))
The other error is
Error: [$injector:modulerr] Failed to instantiate module app due to:
[$injector:modulerr] Failed to instantiate module angularSpinner due to:
[$injector:nomod] Module 'angularSpinner' is not available!
You either misspelled the module name or forgot to load it.
If registering a module ensure that you specify the dependencies as the second argument.
http://errors.angularjs.org/1.4.4/$injector/nomod?p0=angularSpinner
I notice you're not running ngAnnotate on your bower components, but you are running uglify on them. This could be causing your problem.
Try:
var bower = gulp.src(bower_files)
.pipe(concat("bower-expanded.js"))
.pipe(ngAnnotate({
add: true,
single_quotes: true
}))
.pipe(gulp.dest(paths.prod))
.pipe(rename("bower.js"))
.pipe(uglify())
.pipe(gulp.dest(paths.prod + paths.js));
As an aside, it's not an awesome idea to concatenate all of your dependencies into a single file. The browser can handle asynchronously loading multiple JS files and will do so much faster than loading a single, massive JS file.
After reading through various answers in SO the first error usually refers to a forgotten ; in the lines prior to the error.
You can configure the concat task to use ; as a seperator for js files to avoid this.
On the second I agree with #ShaunScovil, also using the .min files provided from each bower package is safer.
You can make use of this main-bower-files package to set this up depending of the env and automate the process of building one or more files of all bower dependencies.
This same thing happens with GruntJS and I recently learned how to fix it. Make sure all of your angular js controllers, directive and filters have proper includes on them.
Example wont work:
angular.module('uniApp').directive('autoFocus', function ($timeout) {
return function (scope, element, attrs) {
scope.$watch(attrs.autoFocus,
function (newValue) {
$timeout(function () {
element.focus();
});
}, true);
};
});
Notice on the above how the $timeout is not properly included?
Example will work:
angular.module('uniApp').directive('autoFocus',['$timeout', function ($timeout) {
return function (scope, element, attrs) {
scope.$watch(attrs.autoFocus,
function (newValue) {
$timeout(function () {
element.focus();
});
}, true);
};
}]);
Now the $timeout is properly included. Make sure to check this little detail on all controllers, filters, and directives.
I'm doing some studies using the Pixijs library, which I find amazing. I'll also have a look into Fabricjs, that seems to have a smaller footprint.
I've been working with Angularjs for some time now and I like conventions, instead of taking time in each project doing configuration and organizing code differently every time.
I would like to hear from some body who experienced Pixijs (or similar) with a framework to organise the code.
I understand that Angularjs is MVVM, but let me know about any tips or suggestion that you may think of?
I did some research this far and a few things came to my mind, such as Browserify (I do believe in convention instead of configuration like I've mentioned though and maybe this wouldn't be the best tool for me).
Kinda old question, but this is something I was looking for myself when starting out with PIXI, so I hope it could be of help to someone to get started.
I use the Revealing module pattern and separate the application into separate files/modules, and then use Browserify to create the application bundle. The HTML loads the app.js bundle which stems from the app.js source below.
index.html: Load your libs (PIXI et al) in <head> and then your app.js in the <body>.
app.js source example:
(function() {
// App.js is the "bootstrap" that loads dependencies, takes care of pre-loading etc.
// I have a template of this which I copy into any new project and use as a checklist.
var core = require("./core.js"); // Use a dummy module as application-wide namespace for easy access
// Any external modules (f eg node modules) could go here
core.utilityLib = require("node-lib");
// Application modules here
core.myModule = require("./myModule.js");
// core.myModule2 = require("./myModule2.js"); // .. you get the idea
// Our main application module
core.main = require("./main.js");
// Init function to run when DOM/scripts have loaded
var init = function() {
// I have a generic screen module which sets up PIXI renderer depending on device compatibility using Modernizr (or weapon of choice). To keep it simple for the sake of the example, lets just create our renderer directly:
core.renderer = PIXI.autoDetectRenderer(screen.innerWidth,screen.innerHeight,{resolution:window.devicePixelRatio});
// I also use a generic loader module that wraps PIXI.loader, taking a list of assets from a config file. Let's just call PIXI.loader directly for now:
PIXI.loader
.add({name:"myasset",url:"/myasset.png"})
.on('progress', loadProgressFunction)
.once('complete',loadCompleteFunction)
})
.load();
}
window.onload = init; // Tell browser to call init function when loaded
// Optional loading progress bar
var function = loadProgressCallback(e) {
}
// Call when mandatory assets has been loaded
var loadCompleteFunction = function() {
myModule.init(); // Init any mandatory modules, f eg to instantiate a player
main.init(); // Tell our main application/game module that we're ready to do fancy stuff
}
// Method to make things move
var animate = function() {
// Send juice to modules that needs to be juiced (or use a ticker module on per-module basis).
// core.main.animate();
requestAnimationFrame(animate);
}
requestAnimationFrame(animate); // See comment below
}());
Comment: PIXI has an built-in requestAnimationFrame alias that takes care of fallback. If not using PIXI, you could use Paul Irish' gist.
core.js:
module.exports = {}; // Just a dummy object to create a module scope that all the modules
// can use to communicate with each other, without running into circular reference problems
main.js:
// Main application/game module
module.exports = (function() {
// Dependencies
var core = require("./core.js"); // This way we can easily access all the necessary modules
// Exports
var exports = {}; // Everything put into this object will be "public"
// Vars
var stuff = 1; // Module vars
exports.init = function() {
// Application magic starts here :)
}
// Some other public method ...
exports.publicMethod = function() {
}
// Some private method
var privateMethod = function() {
}
return exports; // Expose public functions to other modules
}());
Any additional modules can be organized in pretty much the same way as main.js.
Run browserify dev/app.js > html_root/app.js each time you want to "compile" your bundle (or create a Makefile, gulp-, node-, or webpack-script - whichever you prefer).
In Angular 1.2, ngRoute is a separate module so you can use other community routers like ui.router instead.
I'm writing an open-source module that aims to work for multiple different router implementations. So how can I check which router is loaded or exists?
I'm doing the following inside a factory in my module, but it does not work the way I expect it to:
if (angular.module("ngRoute"))
// Do ngRoute-specific stuff.
else if (angular.module("ui.router"))
// Do ui.router-specific stuff.
It raises an error for whichever module is not loaded. For example, if the app is using ui.router, then the following error is raised for the ngRoute check:
Uncaught Error: [$injector:nomod] Module 'ngRoute' is not available!
You either misspelled the module name or forgot to load it. If
registering a module ensure that you specify the dependencies as the
second argument.
I am not aware of a way of checking without an error being raised; however, notice that the issue is that it was an Uncaught Error, not that an error was thrown. The pattern for catching such an error is the following.
try { angular.module("ngRoute") } catch(err) { /* failed to require */ }
If an error is caught, you can try the other module, and if not, you can use the first.
If your behavior will be the same for each module, you could do something like the following, in which we define a function which will attempt the first of the listed module names, and if an error is thrown, try the next option.
var tryModules = function(names) {
// accepts a list of module names and
// attempts to load them, in order.
// if no options remain, throw an error.
if( names.length == 0 ) {
throw new Error("None of the modules could be loaded.");
}
// attempt to load the module into m
var m;
try {
m = angular.module(names[0])
} catch(err) {
m = null;
}
// if it could not be loaded, try the rest of
// the options. if it was, return it.
if( m == null ) return tryModules(names.slice(1));
else return m;
};
tryModules(["ngRoute", "ui.router"]);
I would test for the service instead of the module itself.
// In controller
if($injector.has('$route')){
}
if($injector.has('$state')){
}
// In angular config
if($injector.has('$routeProvider')){
}
if($injector.has('$stateProvider')){
}
The original answer is legit. However, as an alternative, I wrote this when I needed to "find or create" the modules. There's a number of use cases, but generally, it lets you not have to worry about file load order. You could either put this in a initialModules.js... or the top of all your individual service/directive files start with something like this. This little function works like a charm for me:
var initialModules = [
{name: 'app.directives', deps: ['ui.mask']},
{name: 'app.services'},
{name: 'app.templates'},
{name: 'app.controllers'}
];
initialModules.forEach(function(moduleDefinition) {
findOrCreateModule(moduleDefinition.name, moduleDefinition.deps);
});
function findOrCreateModule(moduleName, deps) {
deps = deps || [];
try {
angular.module(moduleName);
} catch (error) {
angular.module(moduleName, deps);
}
}
///// OR... in like "myDirective.js"
findOrCreateModule('app.directives').directive('myDirective', myDirectiveFunction);
If you decorate angular.module to store the names in an array then you could just check if the array contains your module name.
Decorate angular.module
See #dsfq's answer on SO.
This needs to happen after angular is loaded but before you start loading any angular modules.
Check for your module
if(angular.modules.indexOf("ngRoute") > -1) ...
The problem of automatically load or create a module could be better solved by something like gulp-angular-filesort, though.
It works really flawlessly.
From gulp-angular-filesort github page:
Automatically sort AngularJS app files depending on module definitions and usage
Used in conjunction with gulp-inject to inject your AngularJS application files (scripts) in a correct order, to get rid of all Uncaught Error: [$injector:modulerr].
Disclaimer: I'm not affiliated with gulp-angular-filesort, I only use it with a lot of profit.
A much better solution is to simply do your check when the module is created. You just need a utility function to add a callback.
//create a utility function to add a callback to object methods
//here we are making it a method of the underscore or lowdash object
//but it could be added to the angular global object or anything else
_.addCallBack = function (obj, originalMethodName, callBackMethod, context){
var fnOriginal = obj[originalMethodName],
outcome;
context = context || obj;
obj[originalMethodName] = function () {
var outcome = fnOriginal.apply(this, arguments);
callBackMethod.apply(this, arguments);
return outcome;
};
};
_.addCallBack(angular, "module", function(sModuleName, asDependencies){
if(_.contains(asDependencies, "ngRoute")){
//your logic here
//just loop through if you don't use underscore or lowdash
}
});
AngularJS 1.6.3 and up has a way to check if a module is loaded via the $injector service.
Also added in 1.6.7 was the ability to load new modules which may be of interest to some.
Consider the following jfiddle http://jsfiddle.net/bchapman26/9uUBU/29/
//angular.js example for factory vs service
var app = angular.module('myApp', ['module1', 'module2']);
var service1module = angular.module('module1', []);
service1module.factory('myService', function() {
return {
sayHello: function(text) {
return "Service1 says \"Hello " + text + "\"";
},
sayGoodbye: function(text) {
return "Service1 says \"Goodbye " + text + "\"";
}
};
});
var service2module = angular.module('module2', []);
service2module.factory('myService', function() {
return {
sayHello: function(text) {
return "Service2 says \"Hello " + text + "\"";
},
sayGoodbye: function(text) {
return "Service2 says \"Goodbye " + text + "\"";
}
};
});
function HelloCtrl($scope, myService) {
$scope.fromService1 = myService.sayHello("World");
}
function GoodbyeCtrl($scope, myService) {
$scope.fromService2 = myService.sayGoodbye("World");
}
I have 2 modules (module1 and module2). Both module1 and module2 define a service called myService. This appears to create a name clash on myService within Angular when both modules are imported into myApp. It appears AngularJs just uses the second service definition without warning you of the possible issue.
Very large projects (or just reusing modules in general) would have a risk of names clashing, which could be difficult to debug.
Is there a way to prefix names with the module name so that name clashes don't happen?
As of today, AngularJS modules do not provide any sort of namespacing that would prevent collisions between objects in different modules. The reason is that an AngularJS app has a single injector that holds names for all objects without respect to module names.
The AngularJS Developer Guide says:
To manage the responsibility of dependency creation, each Angular
application has an injector. The injector is a service locator that is
responsible for construction and lookup of dependencies.
As you've mentioned, nasty bugs can result when injecting modules into your main/app module. When collisions happen they are silent and the winner is determined by whichever was the last module injected.
So no, there's not a built in way of avoiding these collisions. Maybe this will happen in the future. For large apps where this problem becomes more likely, you're right that naming conventions are your best tool. Consider whether objects belonging to a module or function area might use a short prefix.
You can avoid this situation by using a convention to name your modules so that they always unique.
One approach is to look at how other languages do it. For example in Java the “full name” of the class is based on the name of the file and the folder it’s in. For example if you had a Java file called Bitmap.java in the folder MyArtStuff, the full name of the class would be MyArtStuff.Bitmap
Turns out AngularJS allows you to have dots (.) as part of your module name so you could essentially use the name convention.
For example if a developer create a module called “ModuleA” in the script “MainPage\Module1.js” they should name their module “MainPage.Module1.ModuleA”. Because each path and filename is unique in your app then your module name will be unique.
You would just have to get your developers to follow this convention.
Note as Rockallite points out this will not help with services, controllers, etc having the same name in multiple modules. But you can use a similiar approach to result that and prefix the names of those elements as well.
Ideally AngularJS would have namespaces and in the future it might. Until then the best we can do is do what developers have been doings for over 40 years before namespaces were invented and prefix our elements best we can.
Unfortunately, there is no namespacing in AngularJS. One solution is to use a prefix (another solution may be this!). See the following example:
// root app
const rootApp = angular.module('root-app', ['app1', 'app2']);
// app 1
const app1 = angular.module('app1', []);
app1.controller('app1.main', function($scope) {
$scope.msg = 'App1';
});
// app2
const app2 = angular.module('app2', []);
app1.controller('app2.main', function($scope) {
$scope.msg = 'App2';
})
<!-- angularjs#1.7.0 -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.0/angular.min.js"></script>
<!-- root app -->
<div ng-app="root-app">
<!-- app 1 -->
<div ng-controller="app1.main">
{{msg}}
</div>
<!-- app 2 -->
<div ng-controller="app2.main">
{{msg}}
</div>
</div>
Define your controllers on the module you want the service to be from.
service2Module.controller("ServiceTwoCtrl", function(myService, $scope) {});