I have two modules, like the following ones:
var a = angular.module('a', []);
a.config(['$interpolateProvider', function($interpolateProvider) {
$interpolateProvider.startSymbol('<[');
$interpolateProvider.endSymbol(']>');
}]);
var b = angular.module('b', ['a']);
I'm running some tests, but I can't figure out if the interpolate configuration in a module is being inherited in b module.
Does angular inherit the config of modules into another modules?
Inheritance isn't the issue here, you are configuring a provider that is used by both modules, and angular is going to apply each config in the order that you register them. From the docs:
When bootstrapping, first Angular applies all constant definitions.
Then Angular applies configuration blocks in the same order they were
registered.
You can reset the values of $interpolateProvider start and end symbols, but you cannot have both settings in your application since you are modifying the same provider in each config block.
Here's a plunk showing this in action.
Related
I have an app module defining dependencies (taken from phonecat-Tutorial) in the directory app:
app.module.js:
angular.module('phonecatApp', [
'phoneList' // (*)
]);
Then, in a directory app/phone-list are the module:
phone-list/phone-list.module.js:
angular.module('phoneList', []);
and component:
phone-list/phone-list.component.js:
angular.module('phoneList').component('phoneList', {...});
From registering the module phoneList in the first snippet at (*), how does AngularJS knows where to fetch the module from? Is the mapping from phoneList to phone-list-directory naming a builtin feature?
AngularJS has a dictionnary of modules. The key in this dictionnary is the string that you give your module when you register it with the following line :
angular.module('phoneList', []);
That's why the previous line must always have been executed in javascript before you can use your module by adding a component (like following line) :
angular.module('phoneList').component('phoneList', {...});
or by injecting your module into another module
angular.module('phonecatApp', [
'phoneList'
]);
The code for relevant modules has to be included in scripts included in the page. This is either done by manually adding various script tags or by task runners like grunt, gulp, webpack etc adding them for you.
If dependency module code doesn't exist angular will throw error
In simpler terms - where the code comes from is not angular's responsibility. It has to already exist for angular to work
Consider the following code:
angular.module('app', ['app.core'])
.factory('NameService', function() {
return {
getName: function() { return 'Omar' ;}
};
});
angular.module('app.core', [])
.controller('MainController', function($scope, NameService) {
$scope.name = NameService.getName();
});
<body ng-app="app">
<div ng-controller="MainController">
{{name}}
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
</body>
The result displays "Omar". Note, however, that the NameService is defined in the app module which is not a dependency of the app.core module. I understand depending on each other would be circular but why does this work?
Essentially, every angular application has a single $injector. When a dependency is registered, it's signature is added to the $injector.modules Array. When a specific dependency is invoked, it's signature is retrieved from the array. The $injector does not restrict access to the modules array based on where the registration originated from; any registered dependency is available everywhere in the application.
It's a design flaw in Angular 1.x. It works because Angular keeps a global registry of all services, controllers, factories, directives, and so on. "Installing" a module means putting all its contents into the global registry, using their name as a string key. So a module can still work if it does not register its dependencies, as long as some other module does.
This is actually a pretty common source of errors in large Angular applications, because you can end up using undeclared dependencies without knowing it, so reorganising your app's module structure will break things in nonobvious ways.
Angular 2's module system is better in this respect.
Is there a way to load/specify modules based on conditions inside a controller ?
var app = angular.module('app',['ngRoute']);
app.controller("DemoCtrl",["$scope",function($scope){
var a = true;
if(a)
// Load "Yes" module to app
else
// Load "No" module to app
}]);
There is no direct way to do this in Angular out-of-the-box, however you can consider using the ocLazyLoad module.
The example given on the linked page shows how you could use it for your case:
myApp.controller("MyCtrl", function($ocLazyLoad) {
$ocLazyLoad.load('testModule.js');
});
Unfortunately, NO, at least out of the box with plain Jane Angular. You cannot load more modules into another module after that module has been defined. What you need to do is move the logic to conditionally load the module when defining your module.
The other option is to used the ocLazyLoad https://github.com/ocombe/ocLazyLoad tool to lazy load your modules.
I am trying to minify and uglify my angularjs + typescript app using grunt-minified. Currently I am getting an error that my main module for the app is not available when I minify. I know why this is occuring due variable names no longer matching the names of the modules they reference. How would I set up annotation so angular is able to identify my main module after minification?
declare module BB {
}
module BB.MyModule {
// initialize the module
export var module = angular
// load the dependencies
.module("MyModule", [
// dependancies
]);
}
This basic setup is working fine unminified, but MyModule is not defined when I minify it. How would I go about defining for safe minification?
You have:
declare module BB {
}
Probably BB has been minified to something else. That would make module BB.MyModule be different from BB.
Solution: Your code is already safe for minification if the point where you bootstrap angular https://docs.angularjs.org/api/ng/function/angular.bootstrap is minified through the same pipeline as BB.module is passed through.
Angular's documentation on modules (http://docs-angularjs-org-dev.appspot.com/guide/module) says:
Dependencies
Modules can list other modules as their dependencies.
Depending on a module implies that required module needs to be loaded
before the requiring module is loaded. In other words the
configuration blocks of the required modules execute before the
configuration blocks or the requiring module. The same is true for the
run blocks. Each module can only be loaded once, even if multiple
other modules require it.
I created this example (http://jsbin.com/IRogUxA/34/edit) which creates a controller module that depends on two "mid-level" modules, each of which depend on two "low-level" modules. So, I have two "mid-level" modules and four "low-level" modules.
Clearly, order does not matter in the JS source. In the example above I've defined the high level modules before the low level ones they reference. I understand that Angular makes use of dependency injection to wire up the dependencies, but the way it does so is mysterious to me.
My question: How does one ensure that the config blocks of the various modules are run in the proper order? Or more broadly, how is it that Angular can resolve all of my dependencies when they are defined in any order I choose (within the JS source code)?
All the angular module API methods, such as "config", "factory" etc, are wrapped in a "invokeLater" function. In another word, when the dependency module is evaluated, the module.config, module.factory etc are not really called at that time. Instead those invocations are simply pushed into a queue.
Consider this example:
var demo = angular.module('demo', ['module1']);
demo.config( function( ) {
console.log("In app.config")
} ).run(function(){
console.log("Angular run");
});
angular.module("module1", []).factory('myservice', function(){
return {};
}).controller('mycontroller', function(){} );
For each module it has its own queue: (for the main module "demo")
var invokeQueue = [];
invokeQueue.push("demo.config", xxx);
invokeQueue.push("demo.run", xxx);
For module1:
var invokeQueue = [];
invokeQueue.push("module.factory", xxx);
invokeQueue.push("module.controller", xxx);
Once all the scripts are loaded and DOMContentLoaded event is fired , angular starts actually load/eval all the modules. At this time angular already constructed a full module dependency tree. The dependency module is always loaded first before the main module so in this case module1 will be loaded first and it's invokeQueue is called in the original order(module.factory, module.controller etc). Then back to the main module demo's invokeQueue, demo.config, demo.run
I think it helps to think of modules as their own applications, not relying on ordering of other (external) dependencies.
If order is important, then you can introduce a module that simply composes other modules and coordinates their interactions.
We avoid taking hard module references in our angular.module({moduleName},[deps]) calls, preferring to have those rolled up by a higher level module. That makes testing in isolation lots easier and you can stub out the services you rely on with lighter weight.