AngularJS Initialization Demo (with init)

Demonstrate an initialization service to compensate early $watch or $on triggers during the application bootstrap. See http://wp.me/p1E7sK-hn for explanation.

by manoj

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.2/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.5/angular.min.js"></script>
<div ng-app="myModule" class="wrapper">
    <h2>AngularJS Initialization Demo</h2>
    <p>For details see <a href="http://wp.me/p1E7sK-hn" target="_blank">article</a>
    <div ng-controller="simpleController" class="left">
        <h3>basic example</h3>
        <p ng-show="options.length == 0">loading options...</p>
        <select ng-show="options.length !== 0"
        ng-model="selectedOption"
        ng-options="option.value as option.name for option in options">
        </select>
        
        <div class="log">
            log:
            <ul>
                <li ng-repeat="entry in logentries">{{entry}}</li>
            </ul>
        </div>
    </div>
    <div ng-controller="controllerWithInitialization" class="right">
        <h3>initialization aware</h3>
        <p ng-show="options.length == 0">loading options...</p>
        <select ng-show="options.length !== 0"
        ng-model="selectedOption"
        ng-options="option.value as option.name for option in options">
        </select>
        
        <div class="log">
            log:
            <ul>
                <li ng-repeat="entry in logentries">{{entry}}</li>
            </ul>
        </div>
    </div>
</div>

CSS

div.left,
div.right {
    position: relative;
    float: left;
}
.wrapper {
    width: 100%;
}
.left {
    width: 40%;
}
.right {
    width: 40%;
}
.log {
    margin-top: 10px;
}
ul {
    list-style-type: none;
}

JavaScript

var myModule = angular.module('myModule', []);

myModule.factory('init', function ($q, $rootScope, $browser) {
 
  var initFunctions = [
    'controllerWithInitialization'
  ];
  var registeredInitFunctions = {};
  var initialized = false;
 
  var initApplication = function () {
    var controllerWithInitialization = registeredInitFunctions['controllerWithInitialization'];
 
    var broadcastAppInitialized = function () {
      $browser.defer(function () {
        initialized = true;
        $rootScope.$apply(function () {
          $rootScope.$broadcast('appInitialized');
        });
      });
    };
    controllerWithInitialization.init()
      .then(broadcastAppInitialized);
  };
 
  $rootScope.$on('$routeChangeStart', function () {
    registeredInitFunctions = {};
    initialized = false;
  });
 
  var initAppWhenReady = function () {
    var registeredInitFunctionNames = _.keys(registeredInitFunctions);
    var isRegistered = _.partial(_.contains, registeredInitFunctionNames);
    if (_.every(initFunctions, isRegistered)) {
      initApplication();
      registeredInitFunctions = null;
    }
  };
 
  var init = function (name, dependencies, initCallback) {
    registeredInitFunctions[name] = {
      init: function () {
        var internalDependencies = $q.all(dependencies);
        return internalDependencies.then(initCallback);
      }};
    initAppWhenReady();
  };
 
    init.watchAfterInit = function (scope, expression, listener, deepEqual) {
      scope.$watch(expression, function (newValue, oldValue, listenerScope) {
        if (initialized) {
          listener(newValue, oldValue, listenerScope);
        }
      }, deepEqual);
    };

    init.onAfterInit = function (scope, event, listener) {
      scope.$on(event, function (event) {
        if (initialized) {
          listener(event);
        }
      });
    };
 
  return  init;
});

myModule.service('myService', function($http) {
    $http.defaults.headers.post['Content-Type'] =...