Using AngularJS Modules to Structure an Application

As I explained in Chapter 3, AngularJS shines when it is used to implement complicated applications, and that tends to mean that AngularJS applications have lots of components such as controllers, directives, filters, and services that work together to deliver functionality to the user. Most of the examples I have created to show you features in this book have contained all of the code and markup in a single HTML file, but that just doesn’t work in real projects.

Not only does a single file become unwieldy, but it also makes it hard for several developers to work on the project at the same time.

The solution is to organize the application’s components into separate files and use script elements to reference those files in a central HTML file. You can name and organize your files in any way that makes sense to your project; common approaches include putting all of the components of a given type together (controllers in one file, directives in another) and putting all of the components related to a particular part of the application together (components for user management in one file, components for content management in another).

Tip You can similarly break the HTML markup in your application into multiple files and load the fragments you need as the application runs. I explain how this is done in Chapter 22.

For especially large .0 applications, it is common to create hierarchies of folders for one level of organization (function or component) and then have multiple files for the other level. Whatever approach you settle on, you will need to use modules to organize your code. In the sections that follow, I’ll show you two approaches to using modules to structure an application.

Tip If you are new to AngularJS, then I recommend you start organizing by component type because it is what tends to be at the front of the mind when trying to figure out whether you should express some code as a controller or a directive, for example. You can switch to another organizational style once you have become familiar with the way that AngularJS works.

1. Maintaining a Single Module

The simplest way to move a component to another file is to do so within the same module. To demonstrate this, I have created a file called directives.js and moved the triButton directive from Listing 18-1 to it, as shown in Listing 18-2.

Listing 18-2. The Contents of the directives.js File

angular.module(“exampleApp”)

.directive(“triButton”, function () {

return {

scope: { counter: “=counter” },

link: function (scope, element, attrs) {

element.on(“click”, function (event) {

console.log(“Button click: ” + event.target.innerText);

scope.$apply(function () {

scope.counter++;

});

});

}

}

});

I call the angular.module method and pass in the name of the module defined in the script element of the example.html file. Calling the module method with a single argument tells AngularJS that you want to obtain the Module object that represents a previously defined module, on which you can call methods such as directive to define new functionality. I have already described many of the methods defined by the Module object, and I describe the rest in this chapter. As a reminder, Table 18-3 summarizes the Module methods.

To bring the contents of the new JavaScript file into the application, I need to add a script element to the example.html file, as shown in Listing 18-3.

Listing 18-3. Adding a script Element to the example.html File

<head>

<title>Services and Modules</title>

<script src=”angular.js”></script>

<link href=”bootstrap.css” rel=”stylesheet” />

<link href=”bootstrap-theme.css” rel=”stylesheet” />

<script>

angular.module(“exampleApp”, []) .controller(“defaultCtrl”, function ($scope) {

$scope.data = {

cities: [“London”, “New York”, “Paris”], totalClicks: 0

};

$scope.$watch(‘data.totalClicks’, function (newVal) {

console.log(“Total click count: ” + newVal);

});

});

</script>

<script src=”directives.js”></script>

</head>

I have to add the script element for the directives.js file after the inline script element because the directive is being added to the module that is defined in the example.html file. AngularJS will report an error if the directives.js file is imported before the exampleApp module is defined.

2. Creating a New Module

Keeping everything in a single module is fine for simple applications, but for more complex applications it can be helpful to define multiple modules, especially if you intend to reuse functionality in several projects. In Listing 18-4, you can see how I have changed the directives.js file so that the directive is defined in a new module.

Listing 18-4. Defining a New Module in the directives.js File

angular.module(“customDirectives”, [])

.directive(“triButton”, function () {

return {

scope: { counter: “=counter” },

link: function (scope, element, attrs) {

element.on(“click”, function (event) {

console.log(“Button click: ” + event.target.innerText);

scope.$apply(function () {

scope.counter++;

});

});

}

}

});

The difference is the way that I have called the angular.module method. I have provided two arguments, which tells AngularJS that I want to create a new module. The first argument is the name of the new module, which is customDirectives in this example, and the second is an array containing the names of the modules that my new module depends on. I have used an empty array to indicate that there are no dependencies. In Listing 18-5, you can see how I use my new module in the example.html file.

Listing 18-5. Using the New Module in the example.html File

<head>

<title>Services and Modules</title>

<script src=”angular.js”></script>

<script src=”directives.js”></script>

<link href=”bootstrap.css” rel=”stylesheet” />

<link href=”bootstrap-theme.css” rel=”stylesheet” />

<script>

angular.module(“exampleApp”, [“customDirectives”])

.controller(“defaultCtrl”, function ($scope) {

$scope.data = {

cities: [“London”, “New York”, “Paris”],

totalClicks: 0

};

$scope.$watch(‘data.totalClicks’, function (newVal) {

console.log(“Total click count: ” + newVal);

});

});

</script>

</head>

To use the directive in the directives.js file, I have added the name of the customDirectives module as a dependency of the exampleApp module. I need to declare this dependency because a directive in the new module has been applied to one of the elements in the view managed by the defaultCtrl controller.

Tip Although I moved the script element for the directives.html file in this listing, the application would have worked quite happily if I had left it at the bottom of the head element as in Listing 18-3. AngularJS loads all of its modules before processing dependencies; ordering matters only when you are trying to modify a module defined in another script element.

Source: Freeman Adam (2014), Pro AngularJS (Expert’s Voice in Web Development), Apress; 1st ed. edition.

Leave a Reply

Your email address will not be published. Required fields are marked *