Best Practices:  

Learn Angular the Hard Right Way

 

Best Practices:  

Learn Angular the Hard Right Way

 

Learning AngularJS

  1. Angular can be easy
    1. when you understand core concepts and best practices
  2. Or Angular can be complicated and difficult
    1. when learning from pieced-together online examples & snippets
      1. May not be best way or widely applicable
      2. Not comprehensive

Overview

  • Intro to Core Concepts
  • Best Practices with Code Samples
  • Common Mistakes
  • Best Practices for migrating to Angular 2
  • Style Guides and Other Resources

Why Angular?

From "AngularJS - From Nutshell To Awesome" by Henry Tao

Architectural Principles

Structure

DRY

Testability

SoC - Separation of Concerns

Separating code into distinct sections, so that each section addresses a separate concern.

 

Makes it easier to:

  • Maintain & extend our codebase
  • Reuse code; Stay DRY
  • Test, as each component will do one thing
  • Isolate and fix bugs

Design Patterns

Architectural Pattern - MVC

From "The Art of AngularJS" by Matt Raible

MVC with Angular

From "AngularJS: Introduction and Sample Programs" by Amaury Valdes

A Simple View Controller

From "Learn Simple AngularJS Thanks to Best Practices" by Daniel Mettler

Best Practice #1: Thick Client

SoC for Server vs Client

From "Learn Simple AngularJS Thanks to Best Practices" by Daniel Mettler

Folder Structure

  • Separate 3rd party libraries
    •  
  • By Type?
    •  
  • By Feature?
    •  
    • works better for larger applications
/app /assets /scripts /tests
App/ Controllers/ Services/ Views/
App/ /core /pubs /parks /transport

Best Practice #2: LIFT

  • LLocating our code is easy
  • IIdentify the code at a glance, when I look at file I should know what it contains.
  • FFlat structure as long as we can. Don’t make the file structure too deep, and between 3 and 7 files consider a new folder.
  • T – (T-DRY) Try to stay DRY (do not repeat yourself).

Best Practice #3:
 Single Responsibility

  • Define 1 component per file.

This example defines the app module and its dependencies, defines a controller, and defines a factory all in the same file.

/* avoid */
angular
    .module('app', ['ngRoute'])
    .controller('SomeController', SomeController)
    .factory('someFactory', someFactory);

function SomeController() { }

function someFactory() { }

Single Responsibility

It is best practice to separate each component into its own file.

/* recommended */

// app.module.js
angular
    .module('app', ['ngRoute']);
/* recommended */

// someController.js
angular
    .module('app')
    .controller('SomeController', SomeController);

function SomeController() { }
/* recommended */

// someFactory.js
angular
    .module('app')
    .factory('someFactory', someFactory);

function someFactory() { }

Readable Code

  • Collaboration
  • Maintenance
  • Refactoring

Best Practice #4:

Avoid Global Variables

 

You run the risk of your code being overwritten by any other JavaScript added to the page after yours.

 

Can be hard to keep track of where and when global variables are being used

 

Instead...

Best Practice #5: Use Closures

  • Wrap Angular components in an Immediately Invoked Function Expression (IIFE).
    • An IIFE removes variables from the global scope.
    • An IIFE protects you against naming collisions and many global variables by providing variable scope for each file.

Before...

/* avoid */
// logger.js
angular
    .module('app')
    .factory('logger', logger);

// logger function is added as a global variable
function logger() { }

// storage.js
angular
    .module('app')
    .factory('storage', storage);

// storage function is added as a global variable
function storage() { }

After...

/**
* recommended
*
* no globals are left behind
*/

// logger.js
(function() {
    'use strict';

    angular
        .module('app')
        .factory('logger', logger);

    function logger() { }
})();

// storage.js
(function() {
    'use strict';

    angular
        .module('app')
        .factory('storage', storage);

    function storage() { }
})();

Best Practices for

Naming Conventions

  • Avoid naming collisions
    • Avoid generic names or keywords.
    • Use unique naming conventions with separators for sub-modules.

Best Practices for

Naming Conventions

  • Component names should be descriptive.
  • Name controllers with Pascal casing
    • Controllers start with capital letter
  • Use camel case for all non-controllers
  • Use suffixes to denote various entities
    • Add 'Controller' suffix to all controllers and 'Factory' suffix to all factories, etc.

Best Practices for

Declaring Module Dependencies

 

Modules are containers of Angular components.  Modules can be grouped into 3 categories: 

  • AngularJS modules (ngRoute, ngAnimate)
  • 3rd party modules (kendo, breeze etc.) –  modules that someone else wrote
  • Custom modules - our modules

Best Practices for

Declaring Module Dependencies

  • Define dependencies for each module in each module
  • Define dependencies at specific levels

Best Practices for

Function Naming

  • Anonymous Functions
    • used in one place only
    • smaller functions
    • only if easily readable
  • Named Functions
    • used in larger, more complex functions
    • easier to read and reuse

Best Practice:  Avoid Complex Expressions In HTML

  • Reduces readability
  • Harder to maintain

 

(JS Fiddle Demo)

Patterns

For Registering, Injecting and Defining Components

Register & Inject, Then Function

  • Array can become long and hard to read
angular
     .module('app.pubs', [])
     .controller('Pubs',['core’,’dataservice',Pubs]);
           function Pubs(core, dataservice) {
     //controller goes here
    }

Function, Inject, Register

  • $inject keeps the injection separate
  • avoid ugly array of injectables
  • scroll to see the injections
  • possible issues with dependency sequence
function Pubs(core, dataservice) {
     //controller goes here
    }
    Pubs.$inject = ['core’,’dataservice']);
    angular
     .module('app.pubs', [])
     .controller('Pubs',Pubs]);

Register, Inject, Function

  • can see the injection list right next to the controller’s Parameters
angular
     .module('app.pubs', [])
     .controller('Pubs',Pubs]);        
           Pubs.$inject = ['core’,’dataservice'];
           function Pubs(core, dataservice) {
     //controller goes here
    }

Inject Later with ngAnnotate

  • use with automation tools like Gulp
  • injects the dependencies just by adding the @ngInject Annotation
angular
     .module('app.pubs', [])
     .controller('Pubs',Pubs]);
           /* @ngInject */
           function Pubs(dataservice) {
     //controller goes here
    }

Common Mistakes

  • Too Many Watchers
    • noticeable performance issue at around 2000 watchers
    • Use bind once
  • Using jQuery
    • DOM manipulations via directives

Angular 1 to 2 Best Practices

Avoid:

  • $scope
  • $observe
  • $parse
  • $eval
  • link function

Use:

  • Isolated Scope
  • ControllerAs
  • BindToController
  • ES6 Classes
  • new 1.4 router

 

Style Guides

Sources

  • http://static.raibledesigns.com/repository/presentations/The_Art_of_AngularJS_DeRailed2014.pdf
  • http://dnn-connect.org/community/blogs/dnn-connect-2015-video-learn-simple-angularjs-thanks-to-best-practices
  • Bullet Three
  • http://www.effectiveui.com/blog/2015/04/20/learned-ng-conf-write-angularjs-migration-mind/
  • http://blog.zuehlke.com/en/angularjs-clean-code/
  • http://www.codeproject.com/Articles/869712/AngularJS
  • http://www.nonlinearcreations.com/Digital/how-we-think/articles/2015/03/AngularJS-Best-Practices.aspx

AngularJS Best Practices

By Erica Stanley

AngularJS Best Practices

Angular & Ionic Workshop, 2015

  • 2,938