|
| 1 | +/** |
| 2 | + * AngularJS module "angular-input-modified". |
| 3 | + * |
| 4 | + * @version 1.1.0 |
| 5 | + * @author Slava Fomin II <[email protected]> |
| 6 | + * @licence MIT |
| 7 | + * @copyright Slava Fomin II, Better Solutions, 2014 |
| 8 | + */ |
1 | 9 | (function(window, angular) {
|
2 | 10 | 'use strict';
|
3 | 11 |
|
|
20 | 28 | require: ['?ngModel', '?^form'],
|
21 | 29 | link: function($scope, $element, attrs, controllers) {
|
22 | 30 |
|
| 31 | + var modelName = attrs.ngModel; |
| 32 | + |
23 | 33 | // Handling controllers.
|
24 | 34 | var ngModel = controllers[0];
|
25 | 35 | var ngForm = controllers[1];
|
|
30 | 40 | return;
|
31 | 41 | }
|
32 | 42 |
|
| 43 | + /** |
| 44 | + * Decorates element with proper CSS classes. |
| 45 | + */ |
| 46 | + var toggleCssClasses = function() { |
| 47 | + $animate.addClass($element, (ngModel.modified ? modifiedClassName : notModifiedClassName)); |
| 48 | + $animate.removeClass($element, (ngModel.modified ? notModifiedClassName : modifiedClassName)); |
| 49 | + }; |
| 50 | + |
| 51 | + var updateModified = function(modelName, modified) { |
| 52 | + if (ngForm) { |
| 53 | + var index = ngForm.modifiedModels.indexOf(modelName); |
| 54 | + var exists = (-1 !== index); |
| 55 | + |
| 56 | + if (modified && !exists) { |
| 57 | + // Adding model name to the list of modified models. |
| 58 | + ngForm.modifiedModels.push(modelName); |
| 59 | + ngForm.modifiedCount++; |
| 60 | + } else if (!modified && exists) { |
| 61 | + // Removing model name from the list of modified models. |
| 62 | + ngForm.modifiedModels.splice(index, 1); |
| 63 | + ngForm.modifiedCount--; |
| 64 | + } |
| 65 | + |
| 66 | + ngForm.modified = (ngForm.modifiedCount > 0); |
| 67 | + } |
| 68 | + }; |
| 69 | + |
33 | 70 | // Saving handle to original $setPristine method.
|
34 | 71 | var originalSetPristine = ngModel.$setPristine;
|
35 | 72 |
|
|
51 | 88 | * Augmentation for original $setPristine method.
|
52 | 89 | */
|
53 | 90 | ngModel.$setPristine = function() {
|
| 91 | + |
54 | 92 | // Calling original $setPristine method.
|
55 | 93 | originalSetPristine.apply(this, arguments);
|
56 | 94 |
|
| 95 | + if (ngModel.modified) { |
| 96 | + updateModified(modelName, false); |
| 97 | + } |
| 98 | + |
57 | 99 | // Updating parameters.
|
58 | 100 | ngModel.masterValue = ngModel.$modelValue;
|
59 | 101 | ngModel.modified = false;
|
|
66 | 108 | * Resets input value to the master.
|
67 | 109 | */
|
68 | 110 | ngModel.reset = function() {
|
69 |
| - eval('$scope.' + attrs.ngModel + ' = ngModel.masterValue;'); |
| 111 | + eval('$scope.' + modelName + ' = ngModel.masterValue;'); |
70 | 112 | };
|
71 | 113 |
|
72 |
| - // If parent form element is present for this input. |
73 |
| - if (ngForm) { |
| 114 | + // If parent form element is present for this input and |
| 115 | + // is not yet initialized. |
| 116 | + if (ngForm && 'undefined' === typeof ngForm.modified) { |
| 117 | + |
| 118 | + ngForm.modified = false; |
| 119 | + ngForm.modifiedCount = 0; |
| 120 | + |
| 121 | + // List of modified models. |
| 122 | + ngForm.modifiedModels = []; |
| 123 | + |
74 | 124 | /**
|
75 | 125 | * Resets all form inputs to it's master values.
|
76 | 126 | */
|
|
84 | 134 | }
|
85 | 135 | });
|
86 | 136 | };
|
87 |
| - |
88 |
| - ngForm.modified = false; |
89 |
| - ngForm.modifiedCount = 0; |
90 |
| - } |
91 |
| - |
92 |
| - /** |
93 |
| - * Decorates element with proper CSS classes. |
94 |
| - */ |
95 |
| - var toggleCssClasses = function() |
96 |
| - { |
97 |
| - $animate.addClass($element, (ngModel.modified ? modifiedClassName : notModifiedClassName)); |
98 |
| - $animate.removeClass($element, (ngModel.modified ? notModifiedClassName : modifiedClassName)); |
99 | 137 | }
|
100 | 138 |
|
101 | 139 | /**
|
|
106 | 144 | var initial = true;
|
107 | 145 |
|
108 | 146 | // Watching for model value changes.
|
109 |
| - $scope.$watch(attrs.ngModel, function(value) { |
| 147 | + $scope.$watch(modelName, function(value) { |
110 | 148 | // If master value is not set.
|
111 | 149 | if (initial) {
|
112 | 150 | // Preserving master value.
|
|
115 | 153 | toggleCssClasses();
|
116 | 154 |
|
117 | 155 | } else {
|
| 156 | + |
118 | 157 | // Comparing current input value with preserved master value
|
119 | 158 | // to determine if it's changed.
|
120 | 159 | var modified = !valuesEqual(value, ngModel.masterValue);
|
121 | 160 |
|
122 | 161 | // If modified flag is changed.
|
123 | 162 | if (ngModel.modified !== modified) {
|
124 | 163 |
|
125 |
| - if (ngForm) { |
126 |
| - ngForm.modifiedCount += (modified ? 1 : -1); |
127 |
| - ngForm.modified = (ngForm.modifiedCount > 0); |
128 |
| - } |
| 164 | + updateModified(modelName, modified); |
129 | 165 |
|
130 | 166 | // Setting new flag.
|
131 | 167 | ngModel.modified = modified;
|
|
160 | 196 | if (value1 instanceof Date && value2 instanceof Date) {
|
161 | 197 | // Comparing two dates.
|
162 | 198 | return (value1.getTime() === value2.getTime());
|
| 199 | + } else { |
| 200 | + // Comparing two generic objects using strong comparison. |
| 201 | + return (value1 === value2); |
163 | 202 | }
|
164 | 203 | }
|
165 | 204 |
|
166 |
| - // In all other cases. |
167 |
| - return (value1 === value2); |
| 205 | + // In all other cases using weak comparison. |
| 206 | + return (value1 == value2); |
168 | 207 | }
|
169 | 208 |
|
170 | 209 | /**
|
|
0 commit comments