<!doctype html>
<html ng-app="plunker">
  <head>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.js"></script>
    <script src="example.js"></script>
    <script src="checklist-model.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
  </head>
  <body>

<div ng-controller="DemoCtrl">
  <label ng-repeat="role in roles">
  <input type="checkbox" checklist-model="user.roles" checklist-value="role"> {{role.text}}
</label>
     <button ng-click="user.roles=[];" style="margin-right: 10px">Uncheck all</button>
    <button ng-click="checkNth(0)">Check first</button>
    <button ng-click="checkAll()">Check all</button>
  
  <pre>{{ user.roles | json }}</pre>
</div>
  </body>
</html>
angular.module('plunker', ['checklist-model']);
var DemoCtrl = function ($scope) {
  $scope.roles = [
    {id: 1, text: 'guest'},
    {id: 2, text: 'user'},
    {id: 3, text: 'customer'},
    {id: 4, text: 'admin'}
  ];
  $scope.user = {
    roles: [$scope.roles[1]]
  };
  
  $scope.checkAll = function() {
    // this first method doesn't work
    //$scope.user.roles = $scope.roles; 
    
    // this one work
    for(i=0;i<$scope.roles.length;i++)
        $scope.checkNth(i);
  };
  
  $scope.checkNth = function(i) {
    console.log("first", JSON.stringify($scope.user.roles));
    $scope.user.roles.splice(i, $scope.user.roles.length); 
    console.log("second", JSON.stringify($scope.user.roles));
    $scope.user.roles.push($scope.roles[i])
    console.log("third", JSON.stringify($scope.user.roles));
  }
};
/**
 * Checklist-model
 * AngularJS directive for list of checkboxes
 */

angular.module('checklist-model', [])
.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) {
  // contains
  function contains(arr, item) {
    if (angular.isArray(arr)) {
      for (var i = 0; i < arr.length; i++) {
        if (angular.equals(arr[i], item)) {
          return true;
        }
      }
    }
    return false;
  }

  // add
  function add(arr, item) {
    arr = angular.isArray(arr) ? arr : [];
    for (var i = 0; i < arr.length; i++) {
      if (angular.equals(arr[i], item)) {
        return;
      }
    }    
    arr.push(item);
  }  

  // remove
  function remove(arr, item) {
    if (angular.isArray(arr)) {
      for (var i = 0; i < arr.length; i++) {
        if (angular.equals(arr[i], item)) {
          arr.splice(i, 1);
          return;
        }
      }
    }
  }  

  return {
    restrict: 'A',
    scope: true,
    link: function(scope, elem, attrs) {
      if (elem[0].tagName !== 'INPUT' || !elem.attr('type', 'checkbox')) {
        throw 'checklist-model should be applied to `input[type="checkbox"]`.';
      }

      if (!attrs.checklistValue) {
        throw 'You should provide  `checklist-value`.';
      }

      // link to original model. Initially assigned in $watch
      var model;// = modelGet(scope);
      var value = $parse(attrs.checklistValue)(scope.$parent);

      // local var storing individual checkbox model
      // scope.checked - will be set in $watch

      // exclude recursion
      elem.removeAttr('checklist-model');
      elem.attr('ng-model', 'checked');
      $compile(elem)(scope);

      // watch UI checked change
      scope.$watch('checked', function(newValue, oldValue) {
        if (newValue === oldValue) { 
          return;
        } if (newValue === true) {
          add(model, value);
        } else if (newValue === false) {
          remove(model, value);
        }
      });

      // watch element destroy to remove from model
      elem.bind('$destroy', function() {
        remove(model, value);
      });      

      // watch model change
      scope.$parent.$watch(attrs.checklistModel, function(newArr, oldArr) {
        // need this line to keep link with original model
        model = newArr;
        scope.checked = contains(newArr, value);
      }, true);
    }
  };
}]);