JavaScript and Angular Best Practices

"Best Practices"

IIFE

(function () {

    'use strict';

})(globalVars);

(Immediately Invoked Function Expression)

Modules

var module = module || {};

(function (module) {
    
    'use strict';

    module.something = function() {
        // Do something interesting
    };

})(module);

Variable Declaration

    // avoid
    _someFunction();

    var someVariable = 3;

    // I'm hoisted
    function _someFunction() {
        // do something cool
    }
    // recommended
    var someVariable;

    function _someFunction() {
        // do something cool
    }

    someVariable = 3;
    _someFunction();

JSLint

Module Methods

    // avoid
    angular
        .module('app', [])
        .controller('MainCtrl', function MainCtrl() {

        })
        .service('SomeService', function SomeService() {

        });
    // recommended
    function MainCtrl() {

    }

    function SomeService() {

    }

    angular
        .module('app', [])
        .controller('MainCtrl', MainCtrl)
        .service('SomeService', SomeService);

Controller "as"

    // avoid
    $stateProvider.state('main', {
        url: "/main",
        templateUrl: '/app/main.html',
        controller: 'MainCtrl'
    });

    function MainCtrl($scope) {
        $scope.someObject = {};
        $scope.doSomething = function () {

        };
    }
    // recommended
    $stateProvider.state('main', {
        url: "/main",
        templateUrl: '/app/main.html',
        controller: 'MainCtrl', // or MainCtrl as vm
        controllerAs: 'vm'
    });

    function MainCtrl() {
        var vm = this;

        vm.someObject = {};
        vm.doSomething = function () {

        };
    }

No Logic in Controllers

    // avoid
    function MainCtrl() {

        var vm = this;

        vm.doSomething = function() {
            if (vm.benchPress < 300) {
                return 'Ha ha ha';
            }
            return 'not bad!';
        }
    }
    // recommended
    function MainCtrl(someService) {

        var vm = this;

        vm.doSomething = function() {
            someService.doSomething();
        }

    }

Services

    // avoid
    function AnotherService() {
        var someValue = '';

        return {
            someValue: someValue,
        };
    }
    angular
      .module('app')
      .factory('AnotherService', AnotherService);
    // recommended
    function AnotherService() {

        var AnotherService = {};
        AnotherService.someValue = '';
        return AnotherService;
    }

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

Directives

    // Presentation
    angular.module(appName).directive('brkShowSomething', [_brkShowSomething]);

    function _brkShowSomething() {
        var directive = {
            restrict: 'E',
        };
        return directive;
    }

    // <brk-show-something></brk-show-something>
    // Add behavior
    angular.module(appName).directive('brkDoSomething', [_brkDoSomething]);

    function _brkDoSomething() {
        var directive = {
            restrict: 'A',
        };
        return directive;
    }

    // <brk-show-something brk-do-something></brk-show-something>

Directive Link vs. Controller

    angular.module(appName).directive('brkMyBadAssDirective', [_brkMyBadAssDirective]);

    function brkMyBadAssDirective() {
        var directive = {
            restrict: 'E',
            link: _link,
            controller: Controller,
            controllerAs: 'vm'
        };
        return directive;
    }

    function _link(scope, element, attrs) {
        // ALL dom manipulation goes here
        // wiring up events, etc...
        // I don't get injected but I have access to element
    }

    Controller.$inject = ['SomeService'];
    function Controller(someService) {
        // I'm doing logic and data binding type stuff
        // I execute before link does
    }

Performance

  • Use $watch very sparingly
    • $scope.$watch('someVar', function(){});
  • DO NOT watch functions
    • This includes the view
  • Whenever possible, use 1 time binding (1.3)
    • {{ :: someVar }} or ng-repeat="foo in :: foos"

Thank You

JavaScript and Angular Best Practices

By Dale Alleshouse

JavaScript and Angular Best Practices

  • 1,471