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

app.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider
      .when('/home', {
        templateUrl: 'home.html',
        controller: 'HomeController as vm',
        resolve: {
          dsData: ['dataService',
            function(dataService) {
              return dataService.init();
            }
          ]
        }
      }).when('/data', {
        templateUrl: 'data.html',
        controller: 'DataController as vm',
        resolve: {
          dsData: ['dataService',
            function(dataService) {
              return dataService.init();
            }
          ]
        }
      })
  }
]);
<!DOCTYPE html>
<html>

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    <script data-require="angular.js@1.2.x" src="https://code.angularjs.org/1.2.21/angular.js" data-semver="1.2.21"></script>
    <script data-require="jquery@*" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="http://code.angularjs.org/1.2.14/angular-route.js"></script>
    <script src="app.js"></script>
    <script src="directives.js"></script>
    <script src="controllers.js"></script>
    <script src="data.srv.js"></script>
    <script src="security.srv.js"></script>
    <script src="ngRefresh.js"></script>
    <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
    <script src="http://cdn.datatables.net/1.10.2/js/jquery.dataTables.min.js"></script>
  </head>

  <body ng-controller="MainCtrl" ng-app="app">
    <p>Hello {{name}}!</p>
    <p>
      <a href="#home">Home</a>
      <a href="#data">Data</a>
    </p>
    <div id="ng-app-view" data-ng-view=""></div>
    
    <div id="memory-leak"><a href="#">Memory Leak Test</a></div>
    <i><ul>
      <li>Click Home</li>
      <li>Click Data</li>
      <li>Repeat several times</li>
      <li>Click Memory Leak test to see all instances of Home Controller alive in console.</li>
    </ul>
      The purpose of this is to test ngRefresh.js to clear out memory, as in a complete browser refresh.
      Clearing out the memory from the top-down approach, rather than spending hours tracking down errors.  
      <b>Final answer may require a recursive node traversal to free object references.</b>
    </i>
  </body>

</html>
/* Put your css in here */

<p>Welcome to the home page</p>

<input ng-model="data.myText">

<div ng-show="showMe()">Your text is: {{data.myText}}</div>

<div test-dir></div>
<p>Welcome to the data page</p>
<ul>
  <li ng-repeat="item in dsData">{{item}}</li>
</ul>
<div test-dir></div>


<table id="example" class="display" cellspacing="0" width="100%">
</table>

<script>
  $(document).ready(function() {
    var dt = $('#example').dataTable();
    dt.fnAddData({{dsData}});
} );
</script>
var serviceId = 'dataService';
angular.module('app').service(serviceId, ['$http', dataService]);

function dataService($http) {
  var init = function() {
    console.log("[DataService] init()");
    return $http.get("myData.txt");
  },
    service = {
      init: init
    };

  return service;
}
apples, oranges, bananas, pineapple, strawberries, grapes, cucumber
angular.module('app').controller('MainCtrl', function($scope) {
  $scope.name = 'World';
});

var something = "";
for (var x = 0; x < 65000; x++)
  something += x.toString();

var homeControllerInstance = 0;

angular.module('app').controller('HomeController', ['$scope', 'dsData', 'securityService',
  function($scope, dsData, securityService) {
    var myInstance = homeControllerInstance++;

    $scope.dsData = dsData.data;
    $scope.data = {};
    $scope.data.myText = "Hello World!";
    $scope.data.counter = 0;
    $scope.data.leak = 0;

    $scope.$on("$destroy", function() {
      console.log("[HomeController " + myInstance + "] destroy()");
      delete $scope.dsData;
    });

    //*** CREATING MEMORY LEAK ***
    $("#memory-leak").on('click', function() {
      console.log("[HomeController " + myInstance + "] click() " + $scope.data.counter);
      $scope.data.leak.push($scope.data.counter++);
    });

    function useSomeMemory() {
      var memory = [];
      for (var i = 0; i < 1000; i++) {
        memory.push(something);
      }
      $scope.data.leak = memory;
    }

    $scope.showMe = function() {
      console.log("[HomeController " + myInstance + "] showMe()");
      return $scope.data.myText.length > 0 && securityService.validate();
    }

    useSomeMemory();

    // *** OPTIONAL: CREATE DETACHED DOM ELEMENTS **
    function detachDom() {
      var b = 1000;

      while (b--) {
        var div = document.createElement("div");
        div.className = "mydiv";
        div.innerHTML = "<span></span>";
        document.body.appendChild(div);
      }
      var parents = $("span").parent("div");
      $("span").remove();
    }
    
    //detachDom();
  }
]);

angular.module('app').controller('DataController', function($scope, dsData) {
  $scope.dsData = dsData.data.split(",");

  $scope.$on("$destroy", function() {
    console.log("[DataController] destroy()");
    delete $scope.dsData;
  });

});
angular.module('app').directive('testDir', function () {
  return  {
    template: '<p>Testing directive</p>'
  }
});
var serviceId = 'securityService';
angular.module('app').service(serviceId, ['$http', securityService]);

function securityService($http) {
  var init = function() {},
    validate = function() {
      console.log("[SecurityService] validate()");
      return true;
    },

    service = {
      init: init,
      validate: validate
    };

  return service;
}
(function() {
  'use strict';

  app.run(['$rootScope',
    function($rootScope) {

      var ngViewDivId = "ng-app-view",
        garbageCollection = [];

      // from http://stackoverflow.com/questions/1248302/javascript-object-size
      function roughSizeOf(object) {

        var objectList = [];
        var stack = [object];
        var bytes = 0;

        while (stack.length) {
          var value = stack.pop();

          if (typeof value === 'boolean') {
            bytes += 4;
          } else if (typeof value === 'string') {
            bytes += value.length * 2;
          } else if (typeof value === 'number') {
            bytes += 8;
          } else if (
            typeof value === 'object' && objectList.indexOf(value) === -1
          ) {
            objectList.push(value);

            for (var i in value) {
              stack.push(value[i]);
            }
          }
        }
        return bytes;
      }

      function refreshApp() {
        var host = document.getElementById(ngViewDivId);
        if (host) {
          var mainDiv = $("#" + ngViewDivId);
          $("body").off();
          mainDiv.empty();
          angular.element(host).empty();
        }
      }

      function garbageCollect() {
        angular.forEach(garbageCollection, function(item) {
          // attempting to free scopes
          console.log("[Garbage Collection] Freeing item of size (" + roughSizeOf(item) + " bytes).");
          item = null;
          // do more to free scope?
        });

        garbageCollection = [];
      }

      function logRouting(type, current, next) {
        var curCtrl = (current) ? current.$$route.controller : " start ",
          curSize = (current) ? roughSizeOf(current.scope) : 0,
          nxtCtrl = (next) ? next.$$route.controller : " start ",
          nxtSize = (next) ? roughSizeOf(next.scope) : 0;
        console.log("[Routing " + type + "] from " + curCtrl + " (" + curSize + " bytes)  to " + nxtCtrl + " (" + nxtSize + " bytes)");
      }

      $rootScope.$on('$routeChangeStart',
        function(event, next, current) {
          logRouting("start", current, next);
          refreshApp();
          if (current) {
            garbageCollection.push(current.scope);
          }
        }
      );

      $rootScope.$on('$routeChangeSuccess',
        function(event, next, current) {
          logRouting("success", current, next);
          garbageCollect();
        }
      );

    }
  ]);

}());