SJCNet

SJCNet is the home of architect/developer/techie, Simon Coope.

Structuring an Angular Solution

While working with Angular over the last few months I've been trying to find a suitable way to structure the projects in my solution. My goals were as follows:

  • Provide separation of concerns (SoC) between the different areas of the application.

  • Enable re-use of common directives stored in a separate project.

  • Make it easy for different team members to work on different areas of the application at the same time (e.g. one person working on a controller and template, with another working on a dependent directive).

  • Make it easier to test directives in isolation (where applicable).

To create a project structure that meets the above objectives I've done some investigation online and in code. The results of which I'm going to share now by working through an example of creating a test solution to meet the above goals.

Test Solution

By way of an example, the test solution will contain the following projects:

  • App - This is the main application. This project will contain the main UI logic and will be represented by the sample website.

  • App.Directive - This project will contain a custom directive that will be referenced and used in the main App project.

To create the test solution, we'll use the following tools, libraries and/or frameworks:

Tools

  • WebStorm - This is an excellent IDE developed by JetBrains. It integrates with all the tools needed for a professional Angular development, for example, Node, Bower, Git, etc.

  • Git - Git is a distributed revision control system and source code management system (SCM).

Libraries/Frameworks

  • NodeJS - Node is a platform for building networking and server-side applications.

  • Yeoman - Yeoman is a web scaffolding tool that can be used to scaffold applications that seamlessly integrate other components required to build the desired application. The framework is comprised of three tools: Yo (Yeoman), Grunt and Bower.

  • Grunt - Grunt is a JavaScript task runner that’s used for automation of common tasks like compilation, minification, testing, etc.

  • Bower - Bower is a front-end package manager that runs over git.

Prerequisites

The following must be installed/configured before beginning the steps to create the sample application.

NodeJS

Before starting work on the sample application we need to make sure we have NodeJS installed and configured. If you’ve not got this installed, it’s as simple as visiting the NodeJS website and following the instructions there to install the version relevant to your development environment and operating system.

Yeoman

Once NodeJS is installed we need to install Yeoman. This is done using the Node Package Manager (NPM) so NodeJS must be installed first.

To install Yeoman open the Node command line and run the following command:

npm install -g yo

Running this command will also install Grunt and Bower (as they’re dependencies of Yeoman).

Next, we need to install the Yeoman Angular generator. This is done using the following command:

npm install -g generator-angular

Creating the Sample Solution

The creation of the sample solution will be split into three sections. First we’re going to create the sample projects (App and App.Directive). Then we’re going to create a really simple directive in the App.Directive project and push the project to a Git repository. Then we’re going to use the test directive from the App.Directive project in the App project.

Note: As this is intended to be a quick sample application I won’t be following best practise in some areas, such as, naming conventions and grunt configuration.

Create the App Project

To create the App project open up the Node command line and navigate to the directory to create the project in (or use mkdir to create the directory if it doesn’t exist).

To create the application, we’re going to use the Yeoman Angular App generator. Creating a project using this generator will include all the configuration/components needed in the majority of Angular applications. To create the project (making sure you’re in the new folder) type the following command:

yo angular

After typing this command you’ll receive the following prompts:

  • Would you like to use Sass (with Compass)?
  • Would you like to include Twitter Bootstrap?
  • Which modules would you like to include?

To keep things simple I only selected to include “Twitter Bootstrap”. Yeoman will now create and configure all the files required to initially run the application. Once this has completed run the following command to view the sample website:

grunt serve

When running the website you should see the default Yeoman template page:

Yeoman Template Page

Create the App.Directive Project

To create the App.Directive project simply follow the steps above using a different folder with a different name.

Please note, to create an Angular directive project we wouldn’t normally use the full Angular app generator as that includes lots of files/configuration we don’t need for a directive specific project.

Create the Directive and Push to Git

As this post is about creating a sample Angular solution it’s not within scope to provide an in-depth example of how to create directives and to push work to a Git repository. To that end I’ll simply list the steps I took at a high level.

Step 1: Create the directive in the App.Directive project. My example directive is as follows:

angular.module('SOL.Samples.Angular.Directive')
    .directive('solHelloWorld',
    function () {
        return {
            restrict: 'E',
            scope: { output: '=' },
            replace: true,
            template: '<span>Hello {{output}}</span>'
        }
    }
);

Step 2: At this stage, because we created the App.Directive project using the full Angular generator from Yeoman we could set-up the App.Directive application to include the new directive and check it. We could also write jasmine tests.

Step 3: Now we need to push the changes to a GIT repository. Pushing the App.Directive project to a Git repository means we can reference it in the App project using Bower.

Please Note: To use a Git repository in Bower you have to use SemVerTag conventions for versioning. When using git this is as simple as including a git tag command after committing the code locally (shown below). After which the code must be pushed to the remote repository.

git add -A
git commit –m “v0.0.0 – Initial Commit”
git tag v0.0.0

Reference the App.Directive Project

To reference the App.Directive test directive you created in the previous step, it’s as simple as adding a package using Bower. However, as the App.Directive project is stored in a private repository we have to reference it’s repository. We could instead publish the work to GitHub and make it public in Bower, but for now we’ll assume this is an internal project and we don’t want the code to be publically accessible.

So, to add a reference to the App.Directive project we need to run a command similar to the following (you’ll need to change the repository reference):

bower install https://git.repository.url/sol.samples.angular.directive.git

This step added a “SOL.Samples.Angular.Directive” folder to my “bower_components” folder. This folder contains the full App.Directive project.

Now it’s simply a matter of adding a script reference to the required files in the html and add the App.Directive project as a dependent module to the App project (as follows):

angular.module('SOL.Samples.Angular.App', [
    'ngRoute',
    'SOL.Samples.Angular.Directive'
])

Then we can use the directive in the App project. In my case I added the following element (the 'name' attribute value applies to an object on the scope of my controller):

Conclusion

In this post we created two basic Angular applications using Yeoman (our App and App.Directive projects). Then we pushed the App.Directive project to a Git repository to allow us to reference it in the App project. Finally, we referenced the App.Directive project and configured the use of the test directive we created.

Though the above approach included examples that wouldn’t be used in a real world project, I think the power of this approach is still obvious. Using this approach we can leverage separation of concerns (SoC) and move our directives into a different module where we can reference them as required. This separation means development work can be neatly divided so one engineer could work on the directive without impacting work on the main application. Then when the directive is ready for use, it can be re-versioned and pushed up to the Git repository for consumption. Furthermore, having the directives in a separate Angular module means we can test the directive in isolation.

Please feel free to comment...

Author image
About Simon Coope
Sydney, Australia Website
Experienced developer/consultant. Loves all things development, technology, gadgets, football and running.