Lessons from the AngularJS Style Guide

These are my favorite style suggestions for creating more manageable AngularJS application they grow and scale. Each of the style points reference a specific item in the Angular style guide. Outside of these I have other more specific pattern and workflow related suggestions at the end of the document.

Style guide Based Recommendations

Application Structure

[Style Y140] (https://github.com/johnpapa/angular-styleguide#style-y140)

  • Structure your app such that you can Locate your code quickly, Identify the code at a glance, keep the Flattest structure you can, and Try to stay DRY. The structure should follow these 4 basic guidelines.
  • Locating our code is easy
  • Identify code at a glance
  • Flat structure as long as we can
  • Try to stay DRY (Don’t Repeat Yourself) or T-DRY

Folders-by-Feature Structure

[Style Y152] (https://github.com/johnpapa/angular-styleguide#style-y152)

  • Create folders named for the feature they represent. When a folder grows to contain more than 7 files, start to consider creating a folder for them. Your threshold may be different, so adjust as needed.
  • I take this note further and also make each feature a its own angular module which must be included explicitly in the application’s main injector.
  • This example below is not exhaustive, but the basic idea carries. We tend to to build components by feature (or story) rather than by component type. This folder structure pattern is designed to help developers in this workflow as well as better communicate modularity.

This traditional MVC structure

- App
— Views
— — FooView.html
— Controllers
— — FooController.js
— Models
— — FooModel.js
— App.js

Becomes

- App
— Foo
— — Foo.html
— — Foo.controller.js
— — Foo.model.js
— — Foo.module.js
— App.module.js
— Index.html

Other Immediate ASG based Recommendations

  1. controllerAs Controller Syntax — [Style Y031] https://github.com/johnpapa/angular-styleguide#style-y031
  2. Manually Identify Dependencies — [Style Y091] https://github.com/johnpapa/angular-styleguide#style-y091
  3. JavaScript Closures — [Style Y010] https://github.com/johnpapa/angular-styleguide#style-y010
  4. controllerAs View Syntax — [Style Y030] https://github.com/johnpapa/angular-styleguide#style-y030

Going Further

Templating using Jade and Pre-Processing CSS using Sass

Jade​ is a terse language for writing HTML templates. It’s syntax is very similar to Ruby’s and can be very helpful in speeding up the process of developing HTML templates. Of its many features, it’s most notable for this use case are:

It is an indent based syntax, so no need for closing tags

  • Code folding in IDEs

Mix-ins

  • Hide large HTML blocks, that, although necessary, hurt readability
  • Write reused HTML blocks once and reference include them as needed

Includes

  • Pull in external files when the final HTML file is compiled.

Further, Jade supports HTML.

Sass​, like Jade, is a scripting language for writing CSS. Motivations for using it are similar to those for using Jade. Sass is a superset of CSS, including powerful support for structuring and organizing your styles in a modular way.

  1. Nested styles
  2. Mix-Ins
  3. Includes
  4. Math
  5. Variables
  6. More

This depends on the introduction of a task runner like gulp or grunt with a step configured to use a plugin such as

Pre-processing CSS using sass

Jade Compilation

Caching all HTML templates

When running an angular application, when a template is needed Angular will look for it in the $templateCache keyed using the specified path, if it is not found in the cache, then it will execute a request for it using that path against the application’s web server.

Pre-caching HTML templates introduces a step into the workflow whereby

  1. Templates are discovered
  2. Using the content of the template this line is generated: $templateCache.put(‘<full path to template>’, ‘<template html content>’);
  3. The cached templates are all concatenated into a single template.js file which is included in the index.html as every other script file.

The templates.js file can optionally create a separate module for all templates. So the template.js file will look like:

angular
.module(‘km.templates’, [])
.run([‘$templateCache’, function($templateCache) {
   $templateCache.put(‘<full path to template>’, ‘<template html content>’);
   $templateCache.put(‘<full path to template2>’, ‘<template html content>’);
   $templateCache.put(‘<full path to template3>’, ‘<template html content>’);
}]);

This depends on the introduction of a task runner like gulp or grunt with a step configured to use a plugin such as

Injecting Application Scripts into index.html

As the application grows, managing the names, locations, and order of <script> tags in the index.html file will become tedious. Due to the inevitability of this, it is recommended that this task be automated.

This depends on the introduction of a task runner like gulp or grunt with a step configured to use a plugin such as

Using a task runner

In short, task runners all for automating the development workflow. The two top contenders in this arena are Gulp and Grunt. The main difference between the two is in Gulp tasks are programmed and in Grunt tasks are configured. Personally, I prefer Gulp over grunt because all the tasks are explicitly and intuitively defined in JavaScript. However, both can dramatically improve web application development workflows.

So of the tasks will create a folder for temporary files that

  1. Must be added to the Web Server’s search path when looking for static content
  2. Should be excluded from source control

JSHint

JSHint is all about code quality. Coding styles are not absolute; different developers have different practices, habits, and development environments. Further, JavaScript is a very flexible language which means that when working in teams, coding style clashes are inevitable. For example, using tabs vs spaces, using single quoted strings versus double quoted strings, inline functions, inline conditionals, and so on.

JSHint forces developers to work within a common set of standards for how coding artifacts are structured across the board. Implemented locally it works as any other syntax checker, highlighting errors and warnings. Implemented globally using a task runner it will list similar issues in any file through out the application’s JSHint search space.

Third Party Plugins

These include any module or component that is not a part of the main Angular application like a custom jQuery module and AngularJS fall under this umbrella.

In general you will want to handle these dependencies in two ways

  1. Sandbox them in their own directory structure, separated from each other as well as the Angular application
  2. Use a package management system such as BowerJS to install, uninstall, and track versions for third party modules

As alluded to earlier in this document, this recommendation warrants a new directory titled vendors, components, or, more explicitly, bower_components.

Similar to the injection workflow discussed earlier, these components should be managed in a similar way. The injection module will be reused in conjunction with a module like gulp-main-bower-files ​which will be used to collect the main files for the each third party component main files for injection into index.html. This module depends on the proper structure of the module’s configuration in order to properly discover the main scripts and css files, but assuming it works, developers will rarely have to tamper with the declaration of any dependency in index.html.

Final Words

Don’t hold these suggestions as gospel delivered from the mountain top. Remember that YOU are doing the coding, not the author of some really great blog post you just read. It is important that coding styles are habitual rather than compulsory.

What I like about the style guide referenced is that the rationale associated with each can be understood intuitively and the non platform specific principles transfer to many other development environments.