Say I have two modules (finance2, finance3), and each of them defines a service with the same name (currencyConverter).
If I tell my main module that it depends on just finance2, I can inject the service like this:
angular.module('invoice2', ['finance2'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
However, if I want my invoice2 to depend on both modules, which currencyConverter would be injected? The one from finance2 or the one from finance3? I can control my own modules, but my concern is if you rely on other people modules that define factories with the same name. How does angular deal with that?
angular.module('invoice2', ['finance2','finance3'])
.controller('InvoiceController', ['currencyConverter', function(currencyConverter) {
The last one loaded/processed will win.
If your scripts are:
finance2 (with currencyConverter)
finance3 (with currencyConverter)
Then you will get finance3's currencyConverter when the dependency for currencyConverter is resolved.
If your scripts are:
finance3 (with currencyConverter)
finance2 (with currencyConverter)
Then you will get finance2's currencyConverter when the dependency for currencyConverter is resolved.
Related
The following code is working fine before minifiaction. Essentially, editableOptions is an angular value provided by the angular-xeditable library.
angular.module('common').run(function(editableOptions) {
editableOptions.theme = 'bs3';
}
)
However, when I minify, I get an injection error. I believe this is because editableOptions is getting minfied. How can I reference it differently so that this does not occur? Is there some way of referencing it starting with angular.module('xeditable') ?
Use the minification-safe method of defining injected objects:
angular.module('common').run(
['editableOptions',
function(editableOptions) {
editableOptions.theme = 'bs3';
}
]);
Angular team have a solution to this problem mentioned in one of their tutorials:
https://docs.angularjs.org/tutorial/step_05
A Note on Minification
Since Angular infers the controller's dependencies from the names of arguments to the controller's constructor function, if you were to minify the JavaScript code for PhoneListCtrl controller, all of its function arguments would be minified as well, and the dependency injector would not be able to identify services correctly.
We can overcome this problem by annotating the function with the names of the dependencies, provided as strings, which will not get minified.
This is another style to avoid minification and uglification problems:
function runModule(editableOptions) {
editableOptions.theme = 'bs3';
}
runModule.$inject = ['editableOptions'];
angular.module('common').run(runModule);
Todd Motto Angular Style
Guide
This aids with readability and reduces the volume of code "wrapped"
inside the Angular framework
I want to inject my sub module to main app, but I have injection error
(Error: [ng:areq] http://errors.angularjs.org/1.3.5/ng/areq?p0=SelectionCtrl&p1=not%20aNaNunction%2C%20got%20undefined
it's my main app
and it's my sub module
How can I fix that? Thanks!
You are messing up with module declaration. You declared angular.module('app.newProject') two times.
While creating it first time you registered SelectionCtrl. After that you created another module with same name angular.module('app.newProject,[]') with dependancy and registered TabController1 controller. When you created second module it overrides first one & now it has only TabController1 thats why angular is throwing error SelectionCtrl is required.
There are several appraoches resolve this approach.
Approach 1
Create a module and store it in some variable and use it whenever you want.
var controllerApp = angular.module('app.newProject', [])
.controller('SelectionCtrl',function(){
//code here
});
controllerApp.controller('TabController1',function(){
//your code here
});
Approach 2
Create a module, and whenever you want to use it, use it without dependency.
angular.module('app.newProject', [])
.controller('SelectionCtrl',function(){
//code here
});
angular.module('app.newProject').controller('TabController1',function(){
//your code here
});
Approach 3 (I wouldn't prefer this approach)
Create a module and append you components in linear manners.
angular.module('app.newProject', [])
.controller('SelectionCtrl',function(){
//code here
})
.controller('TabController1',function(){
//your code here
});
I would prefer you to go for Approach 2 which will provide you to bind components any by referring a module.
I'm pretty new to Angular. Sorry for the basic question but I couldn't find info about how to write a library in Angular the proper way.
The reason is to benefit from Angular modules as well as testability/mocks.
The library
I am transferring my code to Angular but a big part of my code is written based on a library that I've developed over a couple of months. Imagine something like underscore.
So my initial thought was to wrap it in an angular module like:
angular.module('mylib', [])
.factory('map', map)
.factory('reduce', reduce)
.factory('find', find);
function map (...
Each factory function is testable and stuff. And then use it like:
angular.module('app', ['mylib'])
.controller('MainCtrl', ['$scope', 'map', MainCtrl]);
function MainCtrl($scope, map) {
... do stuff with map ...
This is fine for a couple of functions I guess but my library has over 20 functions and it's just too much boilerplate to define every one of them as a factory and then inject them into my controller.
Second solution
Another way is to have just one factory that returns an object. Kinda like this:
angular.module('mylib', [])
.factory('mylib', mylib)
function mylib () {
var exports = {};
exports.map = function (...
exports.reduce = function (...
exports.find = function (...
return exports;
}
And then use it like this:
angular.module('app', ['mylib'])
.controller('MainCtrl', ['$scope', 'mylib', MainCtrl]);
function MainCtrl($scope, mylib) {
... do stuff with mylib.map ...
But...
Is this a good approach? What would a good way to write a utility library in Angular and use it? Readability and maintainability are important but I prefer not to have so much boilerplate code.
If your library functions are as generic as your example, I wouldn't try to define them as Angular modules in the first place. Write a plain JS library. That will result in less useless boilerplate, and as a bonus your library will also be usable in non-Angular apps. Angular plays along nicely with libraries that are unaware of it, for example by not requiring data objects to implement anything extra (think ko.observable, Backbone Model, etc) to be usable with data binding.
Being an Angular module is not a requirement for testability. The only thing I can think of that Angular could do to improve testability in a generic utility library is the dependency injection (e.g. injecting a mock service for "current time" into a time library for deterministic results). If you don't need any of that, take the past of least complication and just write a plain JS library.
If wrapping the library in an Angular module is an absolute requirement (for instance to not pollute the global namespace with a short namespace for it), I would still write the library in plain JS, put it into a more complicated namespace, and then alias it with an Angular module.
lib/handy-utilities-1.0.js
// Or any other descriptive namespace
var handyUtilities = {
map: function() { ... }
};
app/util.js
angular.module("handyUtilities", []).constant("util", handyUtilities);
I am curious and still can not explain dependency loop (passed) in this case.
angular.module('mainApp', ['addon.dashboard']).factory('Test', function(){
return {
hello: 'moto'
};
});
angular.module('addon.dashboard', ['mainApp']).controller('Demo', function(Test){
console.log(Test.hello);
});
That is a sample code in my app. The mainApp module require to inject addon.dashboard module. Otherwise, addon.dashboard module require to inject mainApp module.
We can see that it may loop here. But it work in my app. The controller Demo actually output moto into console.
How does angular deal with loop injection like that?
You might want to look into the angular code (especially the loadModules method). Basically there is a HashMap that contains all the modules loaded. If its not in the HashMap, it puts it into that and then goes ahead with initializing the rest of the module. IF its already in the set, it will return immediately.
So, in your case, lets say mainApp gets loaded first. It puts it into loadedModules and the goes to find its dependencies. When it finds addon.dashboard, it finds that mainApp is a dependency, but its already present in loadedModules, so it returns immediately.
Its a lot better if you breakpoint into the "loadModules" method of angular.js
As suggested I wrap all my services into a module, So, I created files to organize them:
myServicesModule.js
var myServices = angular.module('myServices', []);
serviceA.js
myServices.service('serviceA', function(){...});
and serviceB.js
myServices.service('serviceB', function(){...});
etc etc.
As a good practice, we should try to avoid global variables, so is there any way to avoid declaring a global var myServices by something I guess module resolving by name? I understand by putting all services into a single file could solve this issue, but I don't want to create a huge file.
Second parameter of module function (dependencies array) is optional :
If you set the second parameter, it will create the module (and override any existing module with the same name) :
// Create the module
angular.module('foo', []).controller('FooCtrl', function($scope) {
// ...
});
If you do not set the second parameter, it will retrieve the module by its name and fail if module does not exist :
// Retrieve module by its name and fail if module does not exist.
angular.module('foo').controller('FooCtrl', function($scope) {
// ...
});
The angular.module is a global place for creating, registering and
retrieving Angular modules. All modules (angular core or 3rd party)
that should be available to an application must be registered using
this mechanism.
When passed two or more arguments, a new module is created. If passed
only one argument, an existing module (the name passed as the first
argument to module) is retrieved.
So this will work:
angular.module('myServices', []);
angular.module('myServices').service('serviceA', function(){...});
angular.module('myServices').service('serviceB', function(){...});
You don't need create variable for your service. It's possible tot do it that way`(in different files):
For example, file1.js:
angular.module('myServices', []);
file2.js
angular.module('myServices').service('serviceA', function(){...});