Click here to Skip to main content
Click here to Skip to main content

AngularJS: Organizing Your Code With Modules

, 31 Jul 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Learn the JavaScript Module Pattern and See How/Why AngularJS Implements The Pattern

Introduction

There's a lot in the AngularJS library, but in this article I'd like to focus on small, specific topic which I believe will provide a good introduction to Angular.  You do not need any experience with Angular or even JavaScript to understand this article.  Hopefully you'll see some of the benefits to using Angular and try it out.

Background

I have been using Angular for a while, but I like to build samples as I learn so when I originally jumped in I didn't take the time to really think about modules or the JavaScript Module Pattern which can help keep code organized.  That's the whole point: keep code organized.  So, now i've gone back, created this extremely small sample which shows how easy it can be to use modules.  Along the way, I'm hoping it becomes a good introduction to Angular for others.

The Problem With (Most) Articles Which Try To Explain Patterns

Most of the time people try to explain a pattern before the reader ever knows what the pattern is attempting to solve and it basically confuses everyone.  In an effort to make this article as simple as possible, let's first take a look at the problem.  Which problem?  The JavaScript problem that everything is created on the global memory space by default.

Here's what I mean.

JavaScript Default Globals Problem

Imagine you have the following script in your HTML.

<script>
     var isDoingWork = false;
</script>

Scope?

Do you know that variable's scope?
Yes, it is global.  That boolean is actually added to the browser's global window object.  

See It In Action

Here's how you can see that in action.
  1. Download the code samples for this article.
  2. Open the modulePattern.htm in your web browser.
  3. Open up the browser dev tools -- F12(Chrome, IE) or Ctrl-Shift-I (Opera) -- (so you can see the console)
  4. Once you are at the web browser dev tools console, type: isDoingWork<ENTER>
  5. You should see the value as false.  
  6. Now type : isDoingWork = true<ENTER>
  7. Now the vaue is true.  You've altered the value.
  8. You can see that the value has been added to the global window object by doing window.isDoingWork = true<ENTER>

This may create some name-clash and could cause some terrible bugs.  Maybe that sounds like a bit of hype to you?  But suppose you decide to implement one of the new JS libraries which are created every other millisecond.  Suppose you find this great new library named Panacea.js which will solve all your problems.

So you include it in your page like this:

<script src="panacea.js"></script>

As easy as that, you've solved all those problems you had before.  However, since this is a big library and you just wanted the solution you have not looked at every line of the huge (thousands of lines) source file.  Buried somewhere deep inside Panacea.js is the following code:

var isDoingWork = false;

setInterval(function(){isDoingWork = !isDoingWork;}, 3000);

That is some really cool code, you know?

Every 3 seconds, it sets the value of the boolean to the opposite value.  Sweet!

See It In Action

If you want to see this in action you can follow these steps:

  1. Download the code samples for this article.
  2. Open the modulePattern2.htm in your web browser.
  3. Open up the browser dev tools -- F12(Chrome, IE) or Ctrl-Shift-I (Opera) -- (so you can see the console)
  4. Once you are at the web browser dev tools console, type: isDoingWork<ENTER>
  5. Repeat line 4 a few times and you will see that the isDoingWork value is changing approximately every 3 seconds.

Isn't that absolutely fantastic?

My First Point: Module Pattern Is Useful

I had to explain all that, to show you why the JavaScript Module pattern is useful.  I'm having to show you the JavaScript Module pattern so I can show you how it is used / implemented in AngularJS. 

Module Pattern: Encapsulation

So, the deal is, the Module pattern is basically about encapsulation.  Encapsulation should sound familiar if you are an OOP (Object Oriented Programming) devotee -- and I hope you are.  Encapsulation is one of the three basic tenets of OOP.  Another way to say encapsulation is data hiding.  In classical OOP -- which is different than prototypical OOP that JavaScript adheres to -- data hiding is an intrinsic part of building a class template.

In C#, for example, the Animal class encapsulates -- hides our data -- certain values that are associated with our Animal object.  That way, if someone decides to alter those values, she must explicitly decide to do so by instantiating an Animal object and then setting those values.  In JavaScript, we can accidentally set values on the global window object without trying.

public class Animal

{
     // constructor allows user to set the commonName
     public animal(string name)
     {
        this.commonName = name;
     }
     // making commonName private hides (encapsulates) it in the class
     private string commonName;
     //explicitly exposing the value for reading only
     public string CommonName  get { return this.commonName    }
}

The Module pattern has been created to mimic this encapsulation behavior in JavaScript so we don't cloud up the global namespace with all our variables and cause hidden issues which are terribly difficult to find and fix.

Now you know the why, let's look at the how.

Immediately Invoked Function Expression (IIFE)

It seems like every time we want to take a step forward, we have to take one sideways.  Because to get to the JavaScript syntax that will allow us to create the code of the Module Pattern, we have to first learn about a special structure called the Immediately Invoked Function Expression aka (IIFE pronounced "iffy").

The most basic IIFE looks like:

(function(){
   // lines
   // of
   // code
}());

If you've never looked at one of these, it will most likely be very ugly to you.

Immediately Invoked

First of all, the reason the first part of its name is Immediately Invoked is because as soon as the source file which contains this special function is loaded, then the code within the function will run. 

Closer Look At IIFE Syntax

You can see that in the middle of all that syntax is a function.  Take a look as this code snippet where I've broken  up the lines of the code a little bit and numbered some of the lines so we can discuss it.

( // 1.
   function() //2.
   { // 3.
     // lines
     // of
     // code
   }() // 4.
); // 5.

First, take a look at line 2 in the script above.  That line is a normal looking anonymous (unnamed) function declaration.  Then, lines 3 down through 4 are the body of that function.   Finally, line 4 ends with the open close parentheses which tell the JavaScript interpreter to call the function.  Lastly, all of that is wrapped in a special set of parentheses (lines 1 and 5) which seem to belong to no one, but tell the interpreter to call this outer anonymous function, which contains our function.

IIFE Can Take Parameters

All of this odd syntax is made worse when you see one that takes parameters.  It might look something like the following

(function(thing1, thing2){
   // lines
   // of
   // code
}("in string", 382));

Now, you can see that the function can take two parameters which will be referred to inside the function as thing1, thing2.  The values which are sent in, in the example are "in string" and 382. 

Now, that we understand the IIFE syntax, let's create another code example that we'll run and begin to see how the encapsulation works.

(function(){
   var isDoingWork = false;
   console.log("isDoingWork value : " + isDoingWork);
}());

See It In Action

To see this run, take the following steps:

  1. Download the code samples for this article.
  2. Open the modulePattern3.htm in your web browser.
  3. Open up the browser dev tools -- F12(Chrome, IE) or Ctrl-Shift-I (Opera) -- (so you can see the console)
  4. You should see something similar to what is shown the image below

When the method is invoked --which happens immediately after the code is loaded by the JavaScript interpreter -- then the function creates the isDoingWork variable and then calls console.log() to output the value to the console.

Now, let's try the steps we attempted before using the console of the dev tools:

  1. type: isDoingWork<ENTER>

When you do that, you will see that the browser no longer believes that the value isDoingWork is defined.  Even if you try to get the value from the global window object, the browser still doesn't believe the value isDoingWork is defined.   The errors you see will look something like what you see in the next image.

Function Is An Object: Creates Scope

This is because you've now created the isDoingWork variable inside a function -- our anonymous IIFE -- and so that variable is only accessible via that function.  The interesting thing is that all functions in JavaScript are First-Class objects.  That simply means that functions are objects and may be accessed via a variable.  Or, another way of saying that is you can store the reference to a function and get to its variables at a later time.

With our first example, our problem is that we didn't save a reference to our anonymous function so we can never get to the value of isDoingWork again.   That's where our next example comes in.

Function Is An Object: Using this

Since every function is an object, every function has a this variable which provides the developer with a reference to the current object.  To provide access to the outside world to our function and its scope, we can return the this variable -- which will provide a reference to the current object.

However, unless we also add the private variable isDoingWork to the function reference (this) we would not be able to reference the variable.  So to do that we'll change our previous example slightly.  It will now look like the following:

thing = (function(){  // 1.
   this.isDoingWork = false; // 2.
   console.log("isDoingWork value : " + isDoingWork);
   return this; // 3.
}());

You can see that on line 1 we've added a new global variable called thing which will contain the value returned from the anonymous function.  Skip ahead to line 3 in the sample code and you can see that we return the this variable.  That means we've returned a reference to the anonymous function.

On line 2 of the code we also had to add the isDoingWork variable to the this reference so that we can reference that value from outside using the syntax thing.isDoingWork.

See It In Action

To see this run, take the following steps:

  1. Download the code samples for this article.
  2. Open the modulePattern4.htm in your web browser.
  3. Open up the browser dev tools -- F12(Chrome, IE) or Ctrl-Shift-I (Opera) -- (so you can see the console)
  4. You will see the value isDoingWork output to the console, just as you did in the original example.
  5. However, now you have to type thing.isDoingWork to get to the value. 

Module Pattern Conclusion

With this final example the value is successfully encapsulated and another JavaScript library would have to explicitly reference the thing object to get to that value.  It is far less likely that this would happen and this helps us keep the global namespace clean and is better code organization in the long run.  This will make it much easier to maintain our code.

Finally, We Get To AngularJS

Because using the Module Pattern is a Best-Practice, the AngularJS developers have built a module system into the library.

Plunker Code

First of all, you can see the entire AngularJS example by going to this Plunker (http://plnkr.co/edit/js8rbKpIuAuePzLF2DcP?p=preview - opens in a new window/tab).

However, I will show all the code here so we can talk about it more easily.

First of all, let's take a look at the HTML.  

<!DOCTYPE html>
<html ng-app="mainApp">

  <head>
    <meta charset="utf-8" />
    <title>Angular Module Example</title>
    <script data-require="angular.js@1.2.x" src="https://code.angularjs.org/1.2.20/angular.js" data-semver="1.2.20"></script>
    <script src="mainCtrl.js"></script>
    <script src="secondCtrl.js"></script>
  </head>

  <body>
    <div ng-controller="MainCtrl as mc">
      <p>mc refers to MainCtrl which has 
      been added to the angular app module</p>
      <p>Hello {{mc.name}}!</p>
      <ol><li ng-repeat="a in mc.allThings">{{a}}</li></ol>
    </div>
    <div ng-controller="SecondCtrl as sc">
      <p>
        Hello {{sc.name}}
      </p>
      <ol><li ng-repeat="a in sc.allThings">{{a}}</li></ol>
    </div>
  </body>

</html>

Angular Directive: ng-app

Angular defines and uses things called directives.  These directives are basically Angular-defined attributes that the AngularJS compiler (the Angular JavaScript) turns into something else.

Right off, we have applied the ng-app directive and defined a name for our Angular app called mainApp.

mainApp is the beginning of the module pattern as we will see in a moment.  

Included Scripts : Each Is A Module

Now, notice that there are three scripts included in this HTML.

The first one is the required AngularJS library.

However, the other two are Angular Controllers which are implemented as modules.

They are implemented as modules to keep the code separate from each other and from the over all app.

AngularJS : Scope Creation In HTML

Look a bit further down in the HTML and you will see two divs which start with the following:

<div ng-controller="MainCtrl as mc">
<div ng-controller="SecondCtrl as sc">

This is setting up the ng-controller for each of those divs.  Each of those divs has its own scope.  And the name of the first controller is MainCtrl and the second one is SecondCtrl.

The AngularJS compiler will search for those two names as functions within the code you provide (include).

If the AngularJS compiler does not find a function with those names it will throw an error.

mainCtrl.js : First Controller

Let's now take a look inisde the mainCtrl.js file.

You can open it in the Plunker by clicking on it on the left side of the Plunker page.

When you do that, you will see some code that should look familiar.  Well, you will at least recognize that it is all wrapped in an IIFE.

(function() {

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

  app.controller('MainCtrl', function() {
    console.log("in MainCtrl...");
    // vt = virtual this - just shorthand
    vt = this;
    vt.name = 'MainCtrl';
    vt.allThings = ["first", "second", "third"];

  });
})();

That's because we need this code to run when the file (mainCtrl.js) is loaded.

Now, notice that first line of code in the IIFE.

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

That line of code is the Angular way to add a module to the Angular namespace.  In this case, we are adding a module which will represent our application.  This is the application module and we've named it mainApp, which is the same value that is in the ng-app directive on the HTML page.

We also create a local variable named app which we will use inside this function (it is only local to this IIFE) again to add a controller.  

Odd Angular Syntax

Also, please look closely at that first line again.  Notice that we are creating the mainApp module for the first time and since we are, we have to provide any dependencies it may have as an array of strings (representing the names of the dependency libraries).  However, in our case, for this simple example, we do not have any dependencies.  But still Angular requires that we send in an empty array, so it knows we are creating the new module and not attempting to load a module that has already been created.

Hint: You will see us load the mainApp module in the secondCtrl.js and it will make a bit more sense.

Once we've created the mainApp module, we need to add our controller to it.  This is the controller which Angular will expect since we added in the HTML (on the div).

Add the Controller to The App Module

The code to add the controller looks like the following:

app.controller('MainCtrl', function() {
    console.log("in MainCtrl...");
    // vt = virtual this - just shorthand
    vt = this;
    vt.name = 'MainCtrl';
    vt.allThings = ["first", "second", "third"];

  });

To add our controller function, we provide a controller name as a string and the function to the app.controller() function.  In this case we provide an anonymous function.

So, our controller function body are the following lines:

   console.log("in MainCtrl...");
   // vt = virtual this - just shorthand
   vt = this;
   vt.name = 'MainCtrl';
   vt.allThings = ["first", "second", "third"];

In this case, when our controller runs, we output a line to the console.  Then, we rename the this var to vt (virtual this, for convenience) and then we add a name property and an allThings array of strings.

Controller and Encapsulation

That is the code which will run when the controller is called by Angular.  That controller will run when this file is loaded, which is at the beginning when the HTML page is loaded.  That means the controller is added to the app module and these properties are added to the controller object (function).  Since we added the properties to the this variable, we will be able to get to those properties later, but they are encapsulated so they cannot be accidentally altered by everyone.

Now, let's switch back to the place in the HTML where the controller is referenced and used.

First Div

It is our first Div where the MainCtrl controller is referenced and used. It looks like:

<div ng-controller="MainCtrl as mc">
    <p>mc refers to MainCtrl which has 
    been added to the angular app module</p>
    <p>Hello {{mc.name}}!</p>
    <ol><li ng-repeat="a in mc.allThings">{{a}}</li></ol>
 </div>

This div outputs the following section of our web page which looks like what you see in the next image.

Output Created Using Angular Directives

However, it creates that output in a special way, using two Angular Directives:

  1. {{mc.name}}
  2. ng-repeat

The first directive is related to the declaration and reference of the MainCtrl on the Div line.  We tell Angular that we want to reference our MainCtrl function (object) as the term mc.  That's just a nice shorthand that Angular provides.

Now, since we placed some properties on the MainCtrl this object, we can now reference those things via mc and the property name.  We wrap that in the special double brackets {{ }} so the Angular compiler understands this is code that will run, and voila, Angular turns this HTML:

 <p>Hello {{mc.name}}!</p>

into the line:

Hello MainCtrl!

After that, we set up a nice unordered list and use the ng-repeat directive to iterate through each item in our array.

Then Angular iterates through the allThings array and turns the following HTML

<li ng-repeat="a in mc.allThings">{{a}}</li>

into the following output

1. first
2. second
3. third

It's as easy as that.  This is all modularized so our values are not clobbered by anyone else.

SecondCtrl : Almost The Same Thing

Here's the code to SecondCtrl. The code is almost the exact same, except for the place where we retrieve our original app module -- instead of create it for the first time.

(function() {

  var app = angular.module('mainApp');

  app.controller('SecondCtrl', function() {
    console.log("in SecondCtrl...");
    // vt = virtual this - just shorthand
    vt = this;
    vt.name = 'SecondCtrl';
    vt.allThings = ["bacon", "lettuce", "tomato"];

  });
})();

Take a close look at the following line:

var app = angular.module('mainApp');

 

The only difference is that we do not provide the array reference.

That's because the mainApp module already exists and we are wanting to add another new module (SecondCtrl) to it.

Conclusion: Best-Practices

All the other code in the script and the HTML is basically the same, but the important thing here is that all the code is modularized and data is encapsulated to organize our code much better.  It's a best-practice followed by the great Google software devs and it is one that we should follow too.  Learn it, use it, live it.  Big Grin | :-D

 History

First release: 07/31/2014

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

newton.saber
Architect
United States United States
My newest book is Learn Python, Think Python (amazon link opens in new window/tab)
 
My previous book is Object-Oriented JavaScript (See it at Amazon.com)
 
My book, Learn JavaScript - amazon.com link is available at Amazon.
 
My upcoming book, Learn AngularJS - Think AngularJS, will be releasing later in 2014.
 
You can learn more about me and my other books, at, NewtonSaber.com
Follow on   Twitter

Comments and Discussions

 
GeneralGreat approach PinmemberVeljko Zrnic20-Feb-15 13:57 
GeneralRe: Great approach Pinmembernewton.saber20-Feb-15 19:44 
QuestionngAnalytics – AngularJS - Google Analytics embed API PinmemberMember 1126608426-Nov-14 5:14 
SuggestionFunction Is An Object: Using this [modified] Pinmemberruidbrum15-Aug-14 15:58 
GeneralMy vote of 3 PinmemberAxu Hoo6-Aug-14 21:59 
BugIIFE syntax [modified] Pinmemberarchippus2-Aug-14 10:52 
GeneralRe: Basic IIFE syntax is wrong Pinmembernewton.saber3-Aug-14 5:57 
GeneralRe: Basic IIFE syntax is wrong [modified] Pinmemberarchippus3-Aug-14 9:29 
GeneralRe: Basic IIFE syntax is wrong Pinmembernewton.saber3-Aug-14 13:11 
GeneralGood one PinprofessionalShahriar Iqbal Chowdhury/Galib31-Jul-14 21:41 
GeneralRe: Good one Pinmembernewton.saber1-Aug-14 8:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150327.1 | Last Updated 31 Jul 2014
Article Copyright 2014 by newton.saber
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid