You are Here:Home>>Code>>How to create a modular SPA with AngularJS

How to create a modular SPA with AngularJS

Jimmy Bisenius
By | 2017-09-07T12:48:45+00:00 Apr 5, 2017|Code|

In this article, we’re going to look over modularized AngularJS applications, why you should use them, and how to build them.

Before you start, you’re going to need NodeJS installed. If you don’t have it already, simply follow the link.

Also, if you don’t have a Javascript IDE yet, it’s ideal when working on applications like such. My personal recommendation is JetBrains Webstorm, which you can find here, although other great alternatives are Atom, Sublime Text 3, vim, and Brackets(although not all IDE’s, they’re highly modifiable environments for development that may be used as one). You can read 15 Great Free Code Text Editors Alternatives with a roundup on several alternatives.

Source Files

What is AngularJS?

AngularJS is a web application framework built by Google in Javascript. It’s a data binding, scope and modular abilities make it a strong and powerful framework for building web applications. You can find more info about AngularJS at its homepage or you can check out their git repository here.

Modularized AngularJS applications are applications built into small modules, with the purpose being to make the application as flexible, upgradable, and scalable as possible. The ideal modularized AngularJS application has one purpose per file, uses modules to make features and sections of applications easily addable/removable, is buildable, and is built with clean/readable code with comments to help label the application.

Chapter 1 – Configuration

Step 1 – Scaffolding the application

A view at the apps structureFirst, we’re going to scaffold the application. Now that we’re using a modularized structure our application structure is more important, as we have to have a build process. Referencing the image above, create the files and folders in the structure as pictured. Leave the files empty for now, we’ll come back to fill them later.

Step 2 – Include the project css

Moving the dependencies over
Go ahead and download the project source files zip and unzip it. Once you open it, go ahead and navigate into the folder labeled dependencies. Grab the file style.sass and drag it into your /src/sass folder in your project. If you’d like, you can create your own sass/css  code for the project and use that instead.

Step 3 – Include the gulpfile


Now, go back into the previously mentioned dependency folder and drag the gulpfile.js folder into the root of your project. This gulp file will automate your build process for you for this application. If you’re interested in learning more about gulp or creating your own gulpfile, you can view their website.

Step 4 – Install the project dependencies

Running npm install in the terminal

 

Because I’m using node for the project, it makes it very easy to download and install all the dependencies that gulp requires, by utilizing a package.json file in my project. If you’re interested in learning more about NodeJS, check out their website. Go ahead and cd into your project folder and run the commands as pictured above to run the install.

Step 5 – Start Gulp

Running gulp in the terminal

Now, it’s as easy as typing in gulp in your terminal! Make sure you have completed the previous installation step before you proceed, or else

Chapter 2 – Building the core

Step 1 – Creating index.html
<html ng-app="bit.core">
    <head>
        <!-- Require Angular CDN -->
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
        <!-- Require UI Router for Angular -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.4.2/angular-ui-router.min.js"></script>
        <!-- Require Angular Code -->
        <script type="text/javascript" src="/js/all.js"></script>

        <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,800" rel="stylesheet">

        <link rel="stylesheet" href="/css/all.css">

        <base href="/">
        <meta name="fragment" content="!">
    </head>
    <body>
        <div class="container" ui-view></div>
    </body>
</html>

The index.html file, the main template for our web app

We’ll start by adding some code to our index.html file, which you can see in the above example. If you notice, we’ve added a base tag and a meta fragment tag that will help configure our routing. These are very important, so ensure that you set your base accordingly, so angularjs knows from what address to route your application from. In most cases, your base value will be “/”

(function() {
    'use strict';

    // Create the module
    angular.module('bit.core', [
        // Require third-party angular dependencies
        'ui.router',
        //Require first-party angular dependencies 
    ]);
})
});

The core of our web-app

Go ahead and use the code above to create the core module in core.module.js. This is what powers the angular app and should be referenced in your ng-app statement in your index.html file.

Step 3 – Setting up routing
.config(CoreConfig);

// Inject Config Dependencies
CoreConfig.$inject = ['$stateProvider', '$locationProvider', '$httpProvider'];

// Instantiate Application Configuration
function CoreConfig($stateProvider, $locationProvider, $httpProvider) {
    // Setup Routing
    $locationProvider.html5Mode(true).hashPrefix('!');
};

Setting up our routing with UI-Router

Now we’re going to add a config function to our core module to setup the routing, by telling AngularJS what view and controller(state) to goto when a user visits a URL. We’re going togo ahead and use ui-router for this, and set it to HTML5Mode so we don’t see the hideous hashbang.

UI Router is an extremely flexible url routing framework for AngularJS. You can learn more about it here if you’d like as well. Go ahead and add the code above to the module instantiation we discussed earlier. Notice how the functions are handling injections now, you are declaring

Notice how the functions are handling injections now, you are declaring CoreConfig object and setting the $inject prototype array to the dependency needed, and then referencing the dependencies again in the parameters of the function.

Chapter 3 – Building the Todo

Step 1  – Creating the todo module
(function() {
    // Tell application to with strict javascript rules
    'use strict';
    // Define module
    angular.module('bitc.todo', []);

})();

Create the todo module

Now we’re going to go ahead over to todo.module.js and create the todo module. Go ahead and create it exactly as before, no config or anything needed this time either.

Step 2 – Creating the todo controller
(function() {
    'use strict';

    // Reference the module
    angular.module('bit.todo')
        // Create the controller
        .controller('TodoController', TodoController);

    // Inject Controller Dependencies
    TodoController.$inject = [];

    function TodoController() {
        // Use vm (View Manager) instead of $scope for scope variables
        var vm = this;
    }
})();

Creating TodoContorller with VM

Now head over to todo.ctrl.js and we’re going to add some substance. Notice how instead of using the $scope variable to access our scope functions, we’re using a variable called vm (View Manager). This will replace the $scope variable when accessing in scope variables, but for $scope functions you’re still going to have to inject $scope.

Step 3 – Creating the todo route
(function() {
    'use strict';

    angular
        .module('bit.todo')
        .config(TodoConfig);

    TodoConfig.$inject = ['$stateProvider'];

    // Configure Todo Module to setup routing
    function TodoConfig($stateProvider) {
        // Define state Name
        $stateProvider.state('todo', {
            // Definde route URL
            url: '/',
            // Define Route TemplateURL
            templateUrl: '/views/todo.html',
            // Define Route Controller
            controller: 'TodoController',
            // Choose what variable to use for view manager here
            controllerAs: 'vm'
        });
    }
})();

Creating our main route for the application with UI-Router

Let’s head over to todo.route.js and let’s get the route established. We want it to be the homepage so let’s go ahead and put / as the url. As you look further down the page you’re going to notice the controllerAs key that is set to vm. This is dynamic and can be changed, but you’ll have to reference it with that variable in your controller if you choose to.

Step 4 – Creating the todo view
<h1>TODO</h1>
<ul>
    <!—Create the header
    <div class="header">
        Tasks
    </div>
    
</ul>

The initial todo.html file o Now head over to the view file and enter the code above

This will create us a basic view for our todo state which we can integrate everything into later.

Step 5 – Integrating the todo module
(function() {
    'use strict';

    // Create the module
    angular.module('bit.core', [
        // Require third-party angular dependencies
        'ui.router',
        //Require first-party angular dependencies
        'bit.todo'
    ])
        // Setup Application Routes
        .config(CoreConfig);

    // Inject Config Dependencies
    CoreConfig.$inject = ['$stateProvider', '$locationProvider', '$httpProvider'];

    // Instantiate Application Configuration
    function CoreConfig($stateProvider, $locationProvider, $httpProvider) {
        // Setup Routing
        $locationProvider.html5Mode(true).hashPrefix('!');
    };
})();

Injecting the todo module into the application

Now that the todo module is created and runnable, we’re going to integrate it into the core of our application. This is where your really start to see the advantages of modularization, as it’s easy to add and remove whole sections of applications. Add the string ‘bit.todo’ under the first-party dependencies comment. This will integrate the todo module into the app.

Step 6 – Integrating tasks into the controller
vm.tasks = ['Task 1', 'Task 2', 'Task 3', 'Task 4'];

    // Crete method to remove taska and attach method to view manager(formerly known as $scope)
    vm.removeTask = function(task) {
        delete vm.tasks[vm.tasks.indexOf(task)];
    }
}

Creating the tasks array and remove task function

Go back to the todo controller as we’re going to integrate all the functions and variables we need to go live. We’re going to add an array of tasks to the vm variable, and then also create a function to remove a task by it’s text, not by index. Go ahead and add all the code you see above to the controller.

Step 7 – Integrating tasks into the view
<!—Display the list of tasks and create a two-way-data-binding from JS to HTML
<li ng-repeat="task in vm.tasks track by $index" ng-show="vm.tasks.indexOf(task) != -1">
    <input type="checkbox" ng-click="vm.removeTask(task)">
    <span class="label" ng-bind="task"></span>
</li>

Adding in the task ng-repeat

Let’s go back to your task view and add the shown list item into the ul. This item tracks itself by index and repeats over for every instance in the vm.tasks array.

Step 8 – Integrating add task into view
<!—Display the list of tasks and create a two-way-data-binding from JS to HTML
<li ng-repeat="task in vm.tasks track by $index" ng-show="vm.tasks.indexOf(task) != -1">
    <input type="checkbox" ng-click="vm.removeTask(task)">
    <span class="label" ng-bind="task"></span>
</li>

Adding the task input

Finally, we’re going to add one more bit of code before we wrap this application up. Add the input and button shown above just beneath your ul to add an “add task” feature.

Chapter 4 – Live Demo
Step 1 – Creating our server
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;

app.use('/css', express.static(__dirname + '/build/css'));
app.use('/js', express.static(__dirname + '/build/js'));
app.use('/views', express.static(__dirname + '/build/views'));
app.use(function(req, res) {
    res.sendFile(__dirname + '/build/views/index.html');
});

app.listen(port);

console.log("App launched on port " + port + ".");

Creating the server file with express

Now, go ahead into the index.js file and paste this code on in. We’re going to push up a basic node.js server to test out our new application, using express. Make sure any route that’s not an asset redirects into the index.html file as we have above.

Step 2 – Initiating the server

Running the server!

Now, cd into your project folder and run

node index.js

to initiate the server. If you have the PORT environment variable set, it will run on that port, otherwise, it defaults to port 8080.

Step 3 – View the app!
Todo Demo App with AngularJs

The app in action!

At last! Head on over to http://localhost:8080 (or the port of your choice) and have fun!

Conclusion

These concepts are widely used in the industry to make applications easily scalable, and you should use it on every application you make from now on. Also, leave a comment below and show me what applications you’ve built with the modular structure!

Have you enjoyed this article? If so, supports us by sharing this article or Become a Patron!

About the Author:

Jimmy Bisenius
Serial Entrepreneur with a passion for Design and Development. Over 10 years experience with HTML, CSS, and Javascript. Loves everything MEAN stack.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.