2

Recently I have been learning Angular and getting on ok but there is something about the dependency injection that is still not clear to me.

Is there any reason to declare in my app.js file the other pieces of my application (services, controllers etc)?

It seems sometimes tutorials show this and sometimes they dont:

var calculatorApp = angular.module('calculatorApp', [
 'config',
 'ngRoute',  
 'calculatorControllers', //Do I need to declare these comnponents here?
 'calculatorServices'
]);

Equally do I need to declare ALL of the dependencies for the entire app in app.js? It seems I can also declare dependencies in any module (here ngResource is not declared in app.js just in services.js):

var calculatorServices = angular.module('calculatorServices', ['ngResource']);

If dependencies are only passed into the function and not first declared in an array does this mean the libraries are not preloaded, is there a benefit to doing this (calculatorService is not declared in app.js this time):

angular.module('myApp')
.controller('MainCtrl',  function ($scope, $location, calculatorService)

Finally is there any difference in the way these modules are declared? The first doesnt reference the main module, the second example does:

var calculatorServices = angular.module('calculatorServices', ['ngResource']);

angular.module('myApp')
.controller('MainCtrl',  function ($scope, $location, calculatorService)

3 Answers 3

1

General rule of thumb: First parameter is the name, second parameter is the the list of dependencies.

AngularJs, in general, has a very standard way of doing things. All declarations of angular objects follow the same convention:

angular.Object(NameOfObject,ArrayOfDependencies[])

where NameOfObject must be a string and ArrayOfDependencies is an array that contains either string or callback functions.

For example, if you want to declare an angular module with a name called myApp that depends on another angular module with the name of ngAnimate, you do the following:

angular.module('myApp',['ngAnimate']);

If you can't visualize it, let's breakdown into parts. The following code is the same as the single line code above.

var myModuleName = "myApp"; //this is your app name
var myDependenciesArray= ['ngAnimate']; // this is a list of dependencies your app is gonna depend on

angular.module(myModuleName,myDependenciesArray); //voila, module declared!

To answer your question, you will need to know what type of dependencies can be injected to which angular objects. You must not confuse.

module can only take in injection of another module, and cannot take in service types (or provider types to be exact).The following syntax is correct:

angular.module('module1',[]);
angular.module('module2',['module1']) // this is okay, module 2 depends on module1.

If you however do this:

angular.module('module2',['$http']) //this is NOT okay

You will get [$injector:modulerr] thrown by angular because $http is a service name and not a module name.

For the same reason, if you are not declaring a module, then you cannot inject a module in that declaration but have to inject services instead. The following syntax is correct:

angular.module('demo')
   .controller('myCtrl',['$scope',function($scope){}] // this is okay, your controller depends on the $scope service

If you however do this:

angular.module('demo')
    .controller('myCtrl',['ngResource']) // this is NOT okay

You will get [$injector:unpr] thrown by angular, stating that no such provider is found.

Let's answer your questions:

Q: Do you need to inject all your dependencies?

A: Definitely, as long as you need them. But make sure you inject them at the correct position.

Q: If dependencies are only passed into the function and not first declared in an array does this mean the libraries are not preloaded, is there a benefit to doing this?

A: As I have mentioned, the second argument of an angular object can take in an array, and that array can take in callback functions. If you however provide only one callback function, you will have problems later when you minify your JavaScript code.

Your app will break when javascript is minified if you write like this:

angular.module('myApp')
   .controller('demoCtrl',function($scope){}); //will break

Your app will not break when javascript is minified if you write like this:

angular.module('myApp')
   .controller('demoCtrl',['$scope',function($scope){}]

Q: Is there any difference in the way these modules are declared?

A: No. Look at the following:

angular.module('myApp',[])
    .controller('demoCtrl',['$scope',function($scope){}]

The above code can be written like this, and they are the same:

var app = angular.module('myApp',[]);

app.controller('demoCtrl',['$scope',function($scope){}]
Sign up to request clarification or add additional context in comments.

3 Comments

This is a very concise answer, is there any difference between the last 2 examples in the final question and my example where it is done like this: var calculatorServices = angular.module('calculatorServices', ['ngResource']); And it is passed as a dependency of the main app module like this: var calculatorApp = angular.module('calculatorApp', ['calculatorServices']); Are all 3 basically equivelent?
Ah thanks! I think your answer is the best one so far so will mark is as my accepted. Could you enlighten me on one more thing please? In my example the service takes ngResource as a dependency, as a best practice should this be declared once in the main app dependency and then in each module that requires to make decoupling easier, or should it be declared just in the modules that require it?
that boils down to your architecture already, no really right and wrong answer. Both ways are considered good practice, it depends on how you justify it. :)
1

First you only need to declare what you need. If you do not make direct use of a module in the module you are working with, there's no need to include it. Transient includes are handled by the DI injector for you.

Using the list-function format is highly recommended, but you will not notice any difference until you start to minifiy your code for production. If you just use the function angular takes the parameter names for DI. But once your javascript code is minified the parameternames are minified as well. Now the angular DI needs your string array to find the correct names.

2 Comments

ok so if the app.js file has not much in it apart from the routing config does that mean it should only declare a dependency on ngRoute and config and the rest is overkill?
You need to include all modules you are using in your templates. But there's no need to repeat all modules every time. Just list the ones you need in the current module. Angular does all the transient loading for you.
1

If a module depends on services, controllers or directives of other modules they must be injected. However, you do not need to inject the dependencies of your dependencies, since Angular flattens the hierarchy for you.

In your example, the calculatorApp will have available to itself the four dependencies that you injected, as well as anything they depend on in their definitions. However, if your calculatorApp needs to use ngResource directly, it should still inject it in its own definition, because if you decide to rewrite your calculatorServices so that it doesn't need ngResource any more, it will probably not be desirable to rewrite calculatorApp as well.

Note, that in reality, dependencies are only instantiated once. Therefore, if calculatorApp and calculatorServices both inject someDependency, then one instance will be shared among these two modules.

Angular does not perform lazy-loading automatically, so there is little difference if you use the array notation or just pass the object to the function directly. The difference between these two syntaxes is that the array notation will not break during minification and uglification of your app. This is so, because strings are not altered during either of these processes, and variable names can be changed to make the file smaller.

Your last point demonstrates the creation of an angular module and the use of an angular module.

var calculatorServices = angular.module('calculatorServices', ['ngResource']);

This creates an empty calculator services module and injects ngResource into it.

angular.module('myApp')
    .controller('MainCtrl',  function ($scope, $location, calculatorService)

This adds the MainCtrl controller to the already existing myApp module. More about this can be found in the Angular docs.

3 Comments

Thanks great answers, just need a little more clarification of the last point, "This creates an empty calculator services module and injects ngResource into it." - What is actually the difference? As both ways the application works? Is the second way best practice?
Ok, so as I understood from your comment, you don't understand the difference between assigning the value to a variable var myApp = angular.module('myApp', []); and using the angular.module('myApp').controller() directly. Both of these are equivalent, however, the second notation allows you to retrieve a reference to your module in another lexical scope. This is useful when you are putting your application in separate files, and allows you to not pollute your global scope. So in essence you're right, it is a best practice, because relying on a var value may be prone to bugs.
Ok thanks I guess really what I meant was what is the difference between using the second and the first when also adding all dependencies to the main app like var calculatorApp = angular.module('calculatorApp', [ 'config', 'ngRoute', 'calculatorControllers', 'calculatorServices']); Essentially arent they just the same except the second way does it in each separate file and the first way passes them to the main app in the app.js file?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.