<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Directives Example</title>

  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.13/angular-sanitize.min.js"></script>
  <script src="script.js"></script>
  <script src="controllers.js"></script>
  <script src="directives.js"></script>
  <script src="services.js"></script>
 
  <link rel="stylesheet" href="style.css" />
</head>

<body ng-app="App" ng-controller="AppController">
  <div id="container" ng-controller="StoreController as store">
    <h3>Customers</h3>
    <customer info="item" ng-repeat="item in store.customers"></customer>
    <h3>Report</h3>
    <div id="report" ng-bind-html="store.report"></div>
    <button ng-click='store.resetCustomer(0)'>Reset {{store.getCustomer(0).name}}</button>
    <button ng-click='store.resetCustomer(1)'>Reset {{store.getCustomer(1).name}}</button>
  </div>
</body>

</html>
(function(angular) {
  'use strict';

  // intialise App and submodules
  angular.module('App.Controllers', []);
  angular.module('App.Directives', []);
  angular.module('App.Services', []);
  angular.module('App', [
    'ngSanitize',
    'App.Controllers',
    'App.Directives',
    'App.Services'
  ]);

})(window.angular);
angular.module('App.Directives')
  .directive('customer', function() {
    return {
      restrict: 'E',
      transclude: true,
      templateUrl: 'customer-template.html',
      scope: {
        info: '='
      },
      controllerAs: 'customer',
      bindToController: true,
      controller: function($scope, $element) {
        
        // record click:
        this.onChange = function() {
          this.info.clicks++;
        }
        
      }
    };
  });
angular.module('App.Controllers')

// App Controller
.controller('AppController', ['$scope',
  function($scope) {

    // global error handler:
    function _handleError(evt, err) {
      alert('Error: ' + err.process + ' [' + err.statusCode + ', ' + err.error + ']');
    }

    $scope.$on('SERVICE_ERROR', angular.bind(this, _handleError));
  }
])

// Store Controller
.controller('StoreController', ['$scope', '$timeout', 'CustomerDataService',
  function($scope, $timeout, CustomerDataService) {

    this.customers = [];
    this.report = '';

    // fetch customers:
    CustomerDataService.getCustomers()
      .success(angular.bind(this, function(data) {
        this.customers = data.customers;
        angular.forEach(this.customers, function(val, key, obj) {
          obj[key].reset = reset.bind(obj[key]);
        }, this);
      }));

    function reset() {
      this.clicks = 0;
      this.selected = false;
    }

    // reset click count on a customer:
    this.resetCustomer = function(idx) {
      this.getCustomer(idx).reset();
    };
    
    this.getCustomer = function(idx) {
      return this.customers[idx];
    };

    // create report summary: 
    this.createReport = function() {
      this.report = '';
      angular.forEach(this.customers, function(item) {
        this.report += item.name + ': Updated ' + item.clicks + ' times<br/>';
      }, this);
    };

    // monitor for changes:
    $scope.$watch(
      angular.bind(this, function() {
        return this.customers;
      }),
      angular.bind(this, this.createReport),
      true
    );
  }
]);
<label>
  <input type="checkbox" ng-model="customer.info.selected" ng-change="customer.onChange()" />
  <span class="value"><strong>Name: </strong>{{customer.info.name}}</span>
  <span class="value"><strong>Address: </strong>{{customer.info.address}}</span>
</label>
angular.module('App.Services')
  .service('CustomerDataService', ['$http', '$rootScope',
    function($http, $rootScope) {

      // notify app about service error:
      function reportError(process, err) {
        err.process = process;
        $rootScope.$broadcast('SERVICE_ERROR', err);
      }

      // mock service to return dummy data:
      this.getCustomers = function() {
        var request = $http.get('customer-data.json');
        request.error(function(err) {
          reportError('getCustomers', err);
        });
 
        return request;
      };
 
      // service identifier:
      this.toString = function() {
        return 'CustomerDataService';
      };

    }
  ]);
 {
   "customers": [{
     "name": "Kim",
     "address": "1600 Amphitheatre",
     "clicks": 0
   }, {
     "name": "Bob",
     "address": "1010 MyRoad",
     "clicks": 0
   }]
 } 
Angular Modular Example
------

- Separated modules for directives and controllers
- ControllerAs syntax
- HTML Template partials
- Example Service
body {
  font-family: Verdana, sans-serif;
  font-size: 12px;
}
h3 {
  margin-bottom: 4px;
}
h3:first-child {
  margin-top: 0;
}
#container {
  padding: 22px;
  background-color: #EFEFEF;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 3px;
}
customer {
  display: block;
  max-width: 300px;
  padding: 3px 8px;
  border-radius: 5px;
  margin-bottom: 1px;
  background-color: rgba(0, 200, 0, 0.5);
  border: 1px dotted rgba(0, 50, 50, 0.1);
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
#report {
  max-width: 300px;
  background-color: rgba(0, 150, 150, 0.25);
  border: 1px dotted rgba(0, 50, 50, 0.1);
  border-radius: 5px;
  padding: 12px 8px;
  line-height: 18px;
  margin-bottom: 10px;
}
button {
  background-color: rgba(0, 0, 0, 0.75);
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 3px;
  color: #FFF;
  text-shadow: 1px 0px rgba(0, 0, 0, 1);
  outline: none;
  cursor: pointer;
}