1/** 2 * Checklist-model 3 * AngularJS directive for list of checkboxes 4 * https://github.com/vitalets/checklist-model 5 * License: MIT http://opensource.org/licenses/MIT 6 */ 7 8angular.module('checklist-model', []) 9.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) { 10 // contains 11 function contains(arr, item, comparator) { 12 if (angular.isArray(arr)) { 13 for (var i = arr.length; i--;) { 14 if (comparator(arr[i], item)) { 15 return true; 16 } 17 } 18 } 19 return false; 20 } 21 22 // add 23 function add(arr, item, comparator) { 24 arr = angular.isArray(arr) ? arr : []; 25 if(!contains(arr, item, comparator)) { 26 arr.push(item); 27 } 28 return arr; 29 } 30 31 // remove 32 function remove(arr, item, comparator) { 33 if (angular.isArray(arr)) { 34 for (var i = arr.length; i--;) { 35 if (comparator(arr[i], item)) { 36 arr.splice(i, 1); 37 break; 38 } 39 } 40 } 41 return arr; 42 } 43 44 // http://stackoverflow.com/a/19228302/1458162 45 function postLinkFn(scope, elem, attrs) { 46 // exclude recursion, but still keep the model 47 var checklistModel = attrs.checklistModel; 48 attrs.$set("checklistModel", null); 49 // compile with `ng-model` pointing to `checked` 50 $compile(elem)(scope); 51 attrs.$set("checklistModel", checklistModel); 52 53 // getter / setter for original model 54 var getter = $parse(checklistModel); 55 var setter = getter.assign; 56 var checklistChange = $parse(attrs.checklistChange); 57 var checklistBeforeChange = $parse(attrs.checklistBeforeChange); 58 59 // value added to list 60 var value = attrs.checklistValue ? $parse(attrs.checklistValue)(scope.$parent) : attrs.value; 61 62 63 var comparator = angular.equals; 64 65 if (attrs.hasOwnProperty('checklistComparator')){ 66 if (attrs.checklistComparator[0] == '.') { 67 var comparatorExpression = attrs.checklistComparator.substring(1); 68 comparator = function (a, b) { 69 return a[comparatorExpression] === b[comparatorExpression]; 70 }; 71 72 } else { 73 comparator = $parse(attrs.checklistComparator)(scope.$parent); 74 } 75 } 76 77 // watch UI checked change 78 scope.$watch(attrs.ngModel, function(newValue, oldValue) { 79 if (newValue === oldValue) { 80 return; 81 } 82 83 if (checklistBeforeChange && (checklistBeforeChange(scope) === false)) { 84 scope[attrs.ngModel] = contains(getter(scope.$parent), value, comparator); 85 return; 86 } 87 88 setValueInChecklistModel(value, newValue); 89 90 if (checklistChange) { 91 checklistChange(scope); 92 } 93 }); 94 95 function setValueInChecklistModel(value, checked) { 96 var current = getter(scope.$parent); 97 if (angular.isFunction(setter)) { 98 if (checked === true) { 99 setter(scope.$parent, add(current, value, comparator)); 100 } else { 101 setter(scope.$parent, remove(current, value, comparator)); 102 } 103 } 104 105 } 106 107 // declare one function to be used for both $watch functions 108 function setChecked(newArr, oldArr) { 109 if (checklistBeforeChange && (checklistBeforeChange(scope) === false)) { 110 setValueInChecklistModel(value, scope[attrs.ngModel]); 111 return; 112 } 113 scope[attrs.ngModel] = contains(newArr, value, comparator); 114 } 115 116 // watch original model change 117 // use the faster $watchCollection method if it's available 118 if (angular.isFunction(scope.$parent.$watchCollection)) { 119 scope.$parent.$watchCollection(checklistModel, setChecked); 120 } else { 121 scope.$parent.$watch(checklistModel, setChecked, true); 122 } 123 } 124 125 return { 126 restrict: 'A', 127 priority: 1000, 128 terminal: true, 129 scope: true,
130 compile: function(tElement, tAttrs) { 131 if ((tElement[0].tagName !== 'INPUT' || tAttrs.type !== 'checkbox') && (tElement[0].tagName !== 'MD-CHECKBOX') && (!tAttrs.btnCheckbox)) { 132 throw 'checklist-model should be applied to `input[type="checkbox"]` or `md-checkbox`.'; 133 } 134 135 if (!tAttrs.checklistValue && !tAttrs.value) { 136 throw 'You should provide `value` or `checklist-value`.'; 137 } 138 139 // by default ngModel is 'checked', so we set it if not specified 140 if (!tAttrs.ngModel) { 141 // local scope var storing individual checkbox model 142 tAttrs.$set("ngModel", "checked"); 143 } 144 145 return postLinkFn; 146 } 147 }; 148}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.