@angular-wave/angular.ts 0.0.72 → 0.0.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/angular-ts.esm.js +2 -2
  2. package/dist/angular-ts.umd.js +2 -2
  3. package/package.json +1 -1
  4. package/src/animations/animate-js.html +5 -2
  5. package/src/animations/animate-queue.js +1 -1
  6. package/src/animations/animate.js +0 -18
  7. package/src/core/compile/attributes.js +8 -1
  8. package/src/core/compile/compile.spec.js +0 -1
  9. package/src/core/controller/controller.js +9 -3
  10. package/src/core/q/q.js +2 -1
  11. package/src/directive/change/change.js +3 -1
  12. package/src/directive/form/form.js +4 -3
  13. package/src/directive/list/list.js +3 -3
  14. package/src/directive/messages/messages.js +177 -172
  15. package/src/directive/model/model.js +261 -471
  16. package/src/directive/switch/switch.js +4 -4
  17. package/src/router/directives/state-directives.js +2 -9
  18. package/src/router/hooks/core-resolvables.js +5 -3
  19. package/src/router/path/path-utils.js +1 -2
  20. package/src/router/resolve/resolve-context.js +14 -29
  21. package/src/router/state/state-queue-manager.js +1 -2
  22. package/src/router/state/state-service.js +2 -3
  23. package/src/router/transition/transition.js +2 -2
  24. package/src/router/view/view.js +2 -8
  25. package/src/shared/common.js +3 -8
  26. package/src/shared/common.spec.js +1 -19
  27. package/src/shared/hof.js +1 -8
  28. package/src/shared/jqlite/jqlite.js +1 -1
  29. package/src/shared/predicates.js +3 -2
  30. package/src/types.js +2 -3
  31. package/types/animations/animate-queue.d.ts +1 -1
  32. package/types/core/compile/attributes.d.ts +10 -1
  33. package/types/core/q/q.d.ts +4 -2
  34. package/types/directive/form/form.d.ts +3 -1
  35. package/types/directive/messages/messages.d.ts +76 -0
  36. package/types/directive/model/model.d.ts +101 -239
  37. package/types/router/resolve/resolve-context.d.ts +0 -2
  38. package/types/router/transition/transition.d.ts +0 -1
  39. package/types/shared/common.d.ts +0 -3
  40. package/types/shared/hof.d.ts +0 -1
  41. package/types/shared/jqlite/jqlite.d.ts +2 -2
  42. package/types/types.d.ts +4 -2
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  DIRTY_CLASS,
3
3
  EMPTY_CLASS,
4
+ INVALID_CLASS,
4
5
  NOT_EMPTY_CLASS,
5
6
  PRISTINE_CLASS,
6
7
  TOUCHED_CLASS,
@@ -16,10 +17,13 @@ import {
16
17
  isUndefined,
17
18
  isFunction,
18
19
  hasAnimate,
20
+ isBoolean,
21
+ snakeCase,
19
22
  } from "../../shared/utils";
20
23
  import {
21
- addSetValidityMethod,
24
+ isObjectEmpty,
22
25
  nullFormCtrl,
26
+ PENDING_CLASS,
23
27
  setupValidity,
24
28
  } from "../form/form";
25
29
  import { defaultModelOptions } from "../model-options/model-options";
@@ -29,107 +33,23 @@ import { ScopePhase } from "../../core/scope/scope";
29
33
  export const ngModelMinErr = minErr("ngModel");
30
34
 
31
35
  /**
32
- * @ngdoc type
33
- * @name ngModel.NgModelController
34
- * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
35
- * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
36
- * is set.
36
+ *
37
+ * @property {*} $viewValue The actual value from the control's view.
37
38
  *
38
39
  * @property {*} $modelValue The value in the model that the control is bound to.
39
- *
40
40
  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
41
- * the control updates the ngModelController with a new {@link ngModel.NgModelController#$viewValue
42
- `$viewValue`} from the DOM, usually via user input.
43
- See {@link ngModel.NgModelController#$setViewValue `$setViewValue()`} for a detailed lifecycle explanation.
44
- Note that the `$parsers` are not called when the bound ngModel expression changes programmatically.
45
-
46
- The functions are called in array order, each passing
47
- its return value through to the next. The last return value is forwarded to the
48
- {@link ngModel.NgModelController#$validators `$validators`} collection.
49
-
50
- Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
51
- `$viewValue`}.
52
-
53
- Returning `undefined` from a parser means a parse error occurred. In that case,
54
- no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
55
- will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
56
- is set to `true`. The parse error is stored in `ngModel.$error.parse`.
57
-
58
- This simple example shows a parser that would convert text input value to lowercase:
59
- * ```js
60
- * function parse(value) {
61
- * if (value) {
62
- * return value.toLowerCase();
63
- * }
64
- * }
65
- * ngModelController.$parsers.push(parse);
66
- * ```
67
-
41
+ * the control updates the ngModelController with a new `$viewValue` from the DOM, usually via user input.
68
42
  *
69
43
  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
70
44
  the bound ngModel expression changes programmatically. The `$formatters` are not called when the
71
45
  value of the control is changed by user interaction.
72
-
73
- Formatters are used to format / convert the {@link ngModel.NgModelController#$modelValue
74
- `$modelValue`} for display in the control.
75
-
76
- The functions are called in reverse array order, each passing the value through to the
77
- next. The last return value is used as the actual DOM value.
78
-
79
- This simple example shows a formatter that would convert the model value to uppercase:
80
-
81
- * ```js
82
- * function format(value) {
83
- * if (value) {
84
- * return value.toUpperCase();
85
- * }
86
- * }
87
- * ngModel.$formatters.push(format);
88
- * ```
89
- *
90
- * @property {Object.<string, function>} $validators A collection of validators that are applied
91
- * whenever the model value changes. The key value within the object refers to the name of the
92
- * validator while the function refers to the validation operation. The validation operation is
93
- * provided with the model value as an argument and must return a true or false value depending
94
- * on the response of that validation.
95
- *
96
- * ```js
97
- * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
98
- * let value = modelValue || viewValue;
99
- * return /[0-9]+/.test(value) &&
100
- * /[a-z]+/.test(value) &&
101
- * /[A-Z]+/.test(value) &&
102
- * /\W+/.test(value);
103
- * };
104
- * ```
105
46
  *
106
- * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
107
- * perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
108
- * is expected to return a promise when it is run during the model validation process. Once the promise
109
- * is delivered then the validation status will be set to true when fulfilled and false when rejected.
110
- * When the asynchronous validators are triggered, each of the validators will run in parallel and the model
111
- * value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
112
- * is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
113
- * will only run once all synchronous validators have passed.
47
+ * @property {Object.<string, (string, string) => boolean>} $validators A collection of validators that are applied whenever the model value changes.
48
+ * The key value within the object refers to the name of the validator while the function refers to the validation operation.
49
+ * The validation operation is provided with the model value as an argument and must return a true or false value depending on the response of that validation.
114
50
  *
115
- * Please note that if $http is used then it is important that the server returns a success HTTP response code
116
- * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
117
- *
118
- * ```js
119
- * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
120
- * let value = modelValue || viewValue;
121
- *
122
- * // Lookup user by username
123
- * return $http.get('/api/users/' + value).
124
- * then(function resolved() {
125
- * //username exists, this means validation fails
126
- * return $q.reject('exists');
127
- * }, function rejected() {
128
- * //username does not exist, therefore this validation passes
129
- * return true;
130
- * });
131
- * };
132
- * ```
51
+ * @property {Object.<string, function(string, string) => QPromise>} $asyncValidators A collection of validations that are expected to perform an asynchronous validation (e.g. a HTTP request).
52
+ * The validation function that is provided is expected to return a promise when it is run during the model validation process
133
53
  *
134
54
  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever
135
55
  * a change to {@link ngModel.NgModelController#$viewValue `$viewValue`} has caused a change
@@ -147,122 +67,213 @@ export const ngModelMinErr = minErr("ngModel");
147
67
  * @property {boolean} $valid True if there is no error.
148
68
  * @property {boolean} $invalid True if at least one error on the control.
149
69
  * @property {string} $name The name attribute of the control.
150
- *
151
- * @description
152
- *
153
- * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
154
- * The controller contains services for data-binding, validation, CSS updates, and value formatting
155
- * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
156
- * listening to DOM events.
157
- * Such DOM related logic should be provided by other directives which make use of
158
- * `NgModelController` for data-binding to control elements.
159
- * AngularJS provides this DOM logic for most {@link input `input`} elements.
160
- * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
161
- * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
162
- *
163
- * @example
164
- * ### Custom Control Example
165
- * This example shows how to use `NgModelController` with a custom control to achieve
166
- * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
167
- * collaborate together to achieve the desired result.
168
- *
169
- * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
170
- * contents be edited in place by the user.
171
- *
172
- * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
173
- * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
174
- * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
175
- * that content using the `$sce` service.
176
- *
177
70
  */
178
- NgModelController.$inject = [
179
- "$scope",
180
- "$exceptionHandler",
181
- "$attrs",
182
- "$element",
183
- "$parse",
184
- "$animate",
185
- "$timeout",
186
- "$q",
187
- "$interpolate",
188
- ];
189
71
 
190
- /**
191
- *
192
- * @param {*} $scope
193
- * @param {import('../../core/exception-handler').ErrorHandler} $exceptionHandler
194
- * @param {*} $attr
195
- * @param {*} $element
196
- * @param {*} $parse
197
- * @param {*} $animate
198
- * @param {*} $timeout
199
- * @param {*} $q
200
- * @param {*} $interpolate
201
- */
202
- export function NgModelController(
203
- $scope,
204
- $exceptionHandler,
205
- $attr,
206
- $element,
207
- $parse,
208
- $animate,
209
- $timeout,
210
- $q,
211
- $interpolate,
212
- ) {
213
- this.$viewValue = Number.NaN;
214
- this.$modelValue = Number.NaN;
215
- this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
216
- this.$validators = {};
217
- this.$asyncValidators = {};
218
- this.$parsers = [];
219
- this.$formatters = [];
220
- this.$viewChangeListeners = [];
221
- this.$untouched = true;
222
- this.$touched = false;
223
- this.$pristine = true;
224
- this.$dirty = false;
225
- this.$valid = true;
226
- this.$invalid = false;
227
- this.$error = {}; // keep invalid keys here
228
- this.$$success = {}; // keep valid keys here
229
- this.$pending = undefined; // keep pending keys here
230
- this.$name = $interpolate($attr.name || "", false)($scope);
231
- this.$$parentForm = nullFormCtrl;
232
- this.$options = defaultModelOptions;
233
- this.$$updateEvents = "";
234
- // Attach the correct context to the event handler function for updateOn
235
- this.$$updateEventHandler = this.$$updateEventHandler.bind(this);
236
-
237
- this.$$parsedNgModel = $parse($attr.ngModel);
238
- this.$$parsedNgModelAssign = this.$$parsedNgModel.assign;
239
- this.$$ngModelGet = this.$$parsedNgModel;
240
- this.$$ngModelSet = this.$$parsedNgModelAssign;
241
- this.$$pendingDebounce = null;
242
- this.$$parserValid = undefined;
243
- this.$$parserName = "parse";
244
-
245
- this.$$currentValidationRunId = 0;
246
-
247
- this.$$scope = $scope;
248
- this.$$rootScope = $scope.$root;
249
- this.$$attr = $attr;
250
- this.$$element = $element;
251
- this.$$animate = $animate;
252
- this.$$timeout = $timeout;
253
- this.$$parse = $parse;
254
- this.$$q = $q;
255
- this.$$exceptionHandler = $exceptionHandler;
256
-
257
- setupValidity(this);
258
- setupModelWatcher(this);
259
- }
72
+ export class NgModelController {
73
+ static $inject = [
74
+ "$scope",
75
+ "$exceptionHandler",
76
+ "$attrs",
77
+ "$element",
78
+ "$parse",
79
+ "$animate",
80
+ "$timeout",
81
+ "$q",
82
+ "$interpolate",
83
+ ];
84
+
85
+ /**
86
+ * @param {import('../../core/scope/scope').Scope} $scope
87
+ * @param {import('../../core/exception-handler').ErrorHandler} $exceptionHandler
88
+ * @param {import('../../core/compile/attributes').Attributes} $attr
89
+ * @param {import('../../shared/jqlite/jqlite').JQLite} $element
90
+ * @param {import("../../core/parser/parse").ParseService} $parse
91
+ * @param {*} $animate
92
+ * @param {*} $timeout
93
+ * @param {import("../../core/q/q").QPromise<any>} $q
94
+ * @param {*} $interpolate
95
+ */
96
+ constructor(
97
+ $scope,
98
+ $exceptionHandler,
99
+ $attr,
100
+ $element,
101
+ $parse,
102
+ $animate,
103
+ $timeout,
104
+ $q,
105
+ $interpolate,
106
+ ) {
107
+ /** @type {any} The actual value from the control's view */
108
+ this.$viewValue = Number.NaN;
109
+
110
+ /** @type {any} The value in the model that the control is bound to. */
111
+ this.$modelValue = Number.NaN;
112
+ /** @type {any} */
113
+ this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
114
+
115
+ this.$validators = {};
116
+ this.$asyncValidators = {};
117
+ this.$parsers = [];
118
+ this.$formatters = [];
119
+ this.$viewChangeListeners = [];
120
+ this.$untouched = true;
121
+
122
+ /** @type {boolean} */
123
+ this.$touched = false;
124
+
125
+ /** @type {boolean} */
126
+ this.$pristine = true;
127
+
128
+ /** @type {boolean} */
129
+ this.$dirty = false;
130
+
131
+ /** @type {boolean} */
132
+ this.$valid = true;
133
+
134
+ /** @type {boolean} */
135
+ this.$invalid = false;
136
+
137
+ this.$error = {}; // keep invalid keys here
138
+ this.$$success = {}; // keep valid keys here
139
+ this.$pending = undefined; // keep pending keys here
140
+ this.$name = $interpolate($attr["name"] || "", false)($scope);
141
+ this.$$parentForm = nullFormCtrl;
142
+ this.$options = defaultModelOptions;
143
+ this.$$updateEvents = "";
144
+ // Attach the correct context to the event handler function for updateOn
145
+ this.$$updateEventHandler = this.$$updateEventHandler.bind(this);
146
+
147
+ this.$$parsedNgModel = $parse($attr["ngModel"]);
148
+ this.$$parsedNgModelAssign = this.$$parsedNgModel.assign;
149
+ /** @type {import("../../core/parser/parse").CompiledExpression|((Scope) => any)} */
150
+ this.$$ngModelGet = this.$$parsedNgModel;
151
+ this.$$ngModelSet = this.$$parsedNgModelAssign;
152
+ this.$$pendingDebounce = null;
153
+ this.$$parserValid = undefined;
154
+ this.$$parserName = "parse";
155
+
156
+ /** @type {number} */
157
+ this.$$currentValidationRunId = 0;
158
+
159
+ this.$$scope = $scope;
160
+ this.$$rootScope = $scope.$root;
161
+ this.$$attr = $attr;
162
+ this.$$element = $element;
163
+ this.$$animate = $animate;
164
+ this.$$timeout = $timeout;
165
+ this.$$parse = $parse;
166
+ this.$$q = $q;
167
+ this.$$exceptionHandler = $exceptionHandler;
168
+
169
+ this.$$hasNativeValidators = false;
170
+
171
+ setupValidity(this);
172
+ setupModelWatcher(this);
173
+ }
174
+
175
+ set(object, property) {
176
+ object[property] = true;
177
+ }
178
+ unset(object, property) {
179
+ delete object[property];
180
+ }
181
+
182
+ $setValidity(validationErrorKey, state) {
183
+ let that = this;
184
+
185
+ function createAndSet(ctrl, name, value) {
186
+ if (!ctrl[name]) {
187
+ ctrl[name] = {};
188
+ }
189
+ that.set(ctrl[name], value);
190
+ }
191
+
192
+ function unsetAndCleanup(ctrl, name, value) {
193
+ if (ctrl[name]) {
194
+ that.unset(ctrl[name], value);
195
+ }
196
+ if (isObjectEmpty(ctrl[name])) {
197
+ ctrl[name] = undefined;
198
+ }
199
+ }
200
+
201
+ function cachedToggleClass(ctrl, className, switchValue) {
202
+ if (switchValue && !ctrl.$$classCache[className]) {
203
+ ctrl.$$animate.addClass(ctrl.$$element, className);
204
+ ctrl.$$classCache[className] = true;
205
+ } else if (!switchValue && ctrl.$$classCache[className]) {
206
+ ctrl.$$animate.removeClass(ctrl.$$element, className);
207
+ ctrl.$$classCache[className] = false;
208
+ }
209
+ }
210
+
211
+ function toggleValidationCss(ctrl, validationErrorKey, isValid) {
212
+ validationErrorKey = validationErrorKey
213
+ ? `-${snakeCase(validationErrorKey, "-")}`
214
+ : "";
215
+
216
+ cachedToggleClass(
217
+ ctrl,
218
+ VALID_CLASS + validationErrorKey,
219
+ isValid === true,
220
+ );
221
+ cachedToggleClass(
222
+ ctrl,
223
+ INVALID_CLASS + validationErrorKey,
224
+ isValid === false,
225
+ );
226
+ }
227
+
228
+ if (isUndefined(state)) {
229
+ createAndSet(this, "$pending", validationErrorKey);
230
+ } else {
231
+ unsetAndCleanup(this, "$pending", validationErrorKey);
232
+ }
233
+ if (!isBoolean(state)) {
234
+ delete this.$error[validationErrorKey];
235
+ delete this.$$success[validationErrorKey];
236
+ } else if (state) {
237
+ delete this.$error[validationErrorKey];
238
+ this.set(this.$$success, validationErrorKey);
239
+ } else {
240
+ this.set(this.$error, validationErrorKey);
241
+ delete this.$$success[validationErrorKey];
242
+ }
243
+ if (this.$pending) {
244
+ cachedToggleClass(this, PENDING_CLASS, true);
245
+ this.$valid = this.$invalid = undefined;
246
+ toggleValidationCss(this, "", null);
247
+ } else {
248
+ cachedToggleClass(this, PENDING_CLASS, false);
249
+ this.$valid = isObjectEmpty(this.$error);
250
+ this.$invalid = !this.$valid;
251
+ toggleValidationCss(this, "", this.$valid);
252
+ }
253
+
254
+ // re-read the state as the set/unset methods could have
255
+ // combined state in this.$error[validationError] (used for forms),
256
+ // where setting/unsetting only increments/decrements the value,
257
+ // and does not replace it.
258
+ let combinedState;
259
+ if (this.$pending && this.$pending[validationErrorKey]) {
260
+ combinedState = undefined;
261
+ } else if (this.$error[validationErrorKey]) {
262
+ combinedState = false;
263
+ } else if (this.$$success[validationErrorKey]) {
264
+ combinedState = true;
265
+ } else {
266
+ combinedState = null;
267
+ }
268
+
269
+ toggleValidationCss(this, validationErrorKey, combinedState);
270
+ this.$$parentForm.$setValidity(validationErrorKey, combinedState, this);
271
+ }
260
272
 
261
- NgModelController.prototype = {
262
273
  $$initGetterSetters() {
263
274
  if (this.$options.getOption("getterSetter")) {
264
- const invokeModelGetter = this.$$parse(`${this.$$attr.ngModel}()`);
265
- const invokeModelSetter = this.$$parse(`${this.$$attr.ngModel}($$$p)`);
275
+ const invokeModelGetter = this.$$parse(`${this.$$attr["ngModel"]}()`);
276
+ const invokeModelSetter = this.$$parse(`${this.$$attr["ngModel"]}($$$p)`);
266
277
 
267
278
  this.$$ngModelGet = function ($scope) {
268
279
  let modelValue = this.$$parsedNgModel($scope);
@@ -282,11 +293,11 @@ NgModelController.prototype = {
282
293
  throw ngModelMinErr(
283
294
  "nonassign",
284
295
  "Expression '{0}' is non-assignable. Element: {1}",
285
- this.$$attr.ngModel,
296
+ this.$$attr["ngModel"],
286
297
  startingTag(this.$$element),
287
298
  );
288
299
  }
289
- },
300
+ }
290
301
 
291
302
  /**
292
303
  * @ngdoc method
@@ -308,7 +319,7 @@ NgModelController.prototype = {
308
319
  * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
309
320
  * invoked if you only change a property on the objects.
310
321
  */
311
- $render: () => {},
322
+ $render() {}
312
323
 
313
324
  /**
314
325
  * @ngdoc method
@@ -332,7 +343,7 @@ NgModelController.prototype = {
332
343
  return (
333
344
  isUndefined(value) || value === "" || value === null || value !== value
334
345
  );
335
- },
346
+ }
336
347
 
337
348
  $$updateEmptyClasses(value) {
338
349
  if (this.$isEmpty(value)) {
@@ -352,7 +363,7 @@ NgModelController.prototype = {
352
363
  this.$$element[0].classList.add(NOT_EMPTY_CLASS);
353
364
  }
354
365
  }
355
- },
366
+ }
356
367
 
357
368
  /**
358
369
  * @ngdoc method
@@ -375,7 +386,7 @@ NgModelController.prototype = {
375
386
  this.$$element[0].classList.remove(EMPTY_CLASS);
376
387
  this.$$element[0].classList.add(PRISTINE_CLASS);
377
388
  }
378
- },
389
+ }
379
390
 
380
391
  /**
381
392
  * @ngdoc method
@@ -399,7 +410,7 @@ NgModelController.prototype = {
399
410
  this.$$element[0].classList.add(DIRTY_CLASS);
400
411
  }
401
412
  this.$$parentForm.$setDirty();
402
- },
413
+ }
403
414
 
404
415
  /**
405
416
  * @ngdoc method
@@ -422,7 +433,7 @@ NgModelController.prototype = {
422
433
  this.$$element[0].classList.remove(TOUCHED_CLASS);
423
434
  this.$$element[0].classList.add(UNTOUCHED_CLASS);
424
435
  }
425
- },
436
+ }
426
437
 
427
438
  /**
428
439
  * @ngdoc method
@@ -444,7 +455,7 @@ NgModelController.prototype = {
444
455
  this.$$element[0].classList.remove(UNTOUCHED_CLASS);
445
456
  this.$$element[0].classList.add(TOUCHED_CLASS);
446
457
  }
447
- },
458
+ }
448
459
 
449
460
  /**
450
461
  * @ngdoc method
@@ -539,7 +550,7 @@ NgModelController.prototype = {
539
550
  this.$$timeout.cancel(this.$$pendingDebounce);
540
551
  this.$viewValue = this.$$lastCommittedViewValue;
541
552
  this.$render();
542
- },
553
+ }
543
554
 
544
555
  /**
545
556
  * @ngdoc method
@@ -587,7 +598,7 @@ NgModelController.prototype = {
587
598
  }
588
599
  }
589
600
  });
590
- },
601
+ }
591
602
 
592
603
  $$runValidators(modelValue, viewValue, doneCallback) {
593
604
  this.$$currentValidationRunId++;
@@ -691,13 +702,9 @@ NgModelController.prototype = {
691
702
  doneCallback(allValid);
692
703
  }
693
704
  }
694
- },
705
+ }
695
706
 
696
707
  /**
697
- * @ngdoc method
698
- * @name ngModel.NgModelController#$commitViewValue
699
- *
700
- * @description
701
708
  * Commit a pending update to the `$modelValue`.
702
709
  *
703
710
  * Updates may be pending by a debounced event or because the input is waiting for a some future
@@ -705,36 +712,34 @@ NgModelController.prototype = {
705
712
  * usually handles calling this in response to input events.
706
713
  */
707
714
  $commitViewValue() {
708
- const viewValue = this.$viewValue;
709
-
710
715
  this.$$timeout.cancel(this.$$pendingDebounce);
711
716
 
712
717
  // If the view value has not changed then we should just exit, except in the case where there is
713
718
  // a native validator on the element. In this case the validation state may have changed even though
714
719
  // the viewValue has stayed empty.
715
720
  if (
716
- this.$$lastCommittedViewValue === viewValue &&
717
- (viewValue !== "" || !this.$$hasNativeValidators)
721
+ this.$$lastCommittedViewValue === this.$viewValue &&
722
+ (this.$viewValue !== "" || !this.$$hasNativeValidators)
718
723
  ) {
719
724
  return;
720
725
  }
721
726
 
722
727
  if (
723
728
  this.$$lastCommittedViewValue === undefined &&
724
- Number.isNaN(viewValue)
729
+ Number.isNaN(this.$viewValue)
725
730
  ) {
726
731
  return;
727
732
  }
728
733
 
729
- this.$$updateEmptyClasses(viewValue);
730
- this.$$lastCommittedViewValue = viewValue;
734
+ this.$$updateEmptyClasses(this.$viewValue);
735
+ this.$$lastCommittedViewValue = this.$viewValue;
731
736
 
732
737
  // change to dirty
733
738
  if (this.$pristine) {
734
739
  this.$setDirty();
735
740
  }
736
741
  this.$$parseAndValidate();
737
- },
742
+ }
738
743
 
739
744
  $$parseAndValidate() {
740
745
  const viewValue = this.$$lastCommittedViewValue;
@@ -758,7 +763,9 @@ NgModelController.prototype = {
758
763
  }
759
764
  if (isNumberNaN(this.$modelValue)) {
760
765
  // this.$modelValue has not been touched yet...
761
- this.$modelValue = this.$$ngModelGet(this.$$scope);
766
+ this.$modelValue = /** @type {(Scope) => any} */ (this.$$ngModelGet)(
767
+ this.$$scope,
768
+ );
762
769
  }
763
770
  const prevModelValue = this.$modelValue;
764
771
  const allowInvalid = this.$options.getOption("allowInvalid");
@@ -791,7 +798,7 @@ NgModelController.prototype = {
791
798
  that.$$writeModelToScope();
792
799
  }
793
800
  }
794
- },
801
+ }
795
802
 
796
803
  $$writeModelToScope() {
797
804
  this.$$ngModelSet(this.$$scope, this.$modelValue);
@@ -806,7 +813,7 @@ NgModelController.prototype = {
806
813
  },
807
814
  this,
808
815
  );
809
- },
816
+ }
810
817
 
811
818
  /**
812
819
  * @ngdoc method
@@ -864,7 +871,7 @@ NgModelController.prototype = {
864
871
  if (this.$options.getOption("updateOnDefault")) {
865
872
  this.$$debounceViewValueCommit(trigger);
866
873
  }
867
- },
874
+ }
868
875
 
869
876
  $$debounceViewValueCommit(trigger) {
870
877
  let debounceDelay = this.$options.getOption("debounce");
@@ -872,17 +879,19 @@ NgModelController.prototype = {
872
879
  if (isNumber(debounceDelay[trigger])) {
873
880
  debounceDelay = debounceDelay[trigger];
874
881
  } else if (
875
- isNumber(debounceDelay.default) &&
876
- this.$options.getOption("updateOn").indexOf(trigger) === -1
882
+ isNumber(debounceDelay["default"]) &&
883
+ /** @type {string} */ (this.$options.getOption("updateOn")).indexOf(
884
+ trigger,
885
+ ) === -1
877
886
  ) {
878
- debounceDelay = debounceDelay.default;
887
+ debounceDelay = debounceDelay["default"];
879
888
  } else if (isNumber(debounceDelay["*"])) {
880
889
  debounceDelay = debounceDelay["*"];
881
890
  }
882
891
 
883
892
  this.$$timeout.cancel(this.$$pendingDebounce);
884
893
  const that = this;
885
- if (debounceDelay > 0) {
894
+ if (/** @type {number} */ (debounceDelay) > 0) {
886
895
  // this fails if debounceDelay is an object
887
896
  this.$$pendingDebounce = this.$$timeout(() => {
888
897
  that.$commitViewValue();
@@ -894,7 +903,7 @@ NgModelController.prototype = {
894
903
  that.$commitViewValue();
895
904
  });
896
905
  }
897
- },
906
+ }
898
907
 
899
908
  /**
900
909
  * @ngdoc method
@@ -928,7 +937,7 @@ NgModelController.prototype = {
928
937
  $overrideModelOptions(options) {
929
938
  this.$options = this.$options.createChild(options);
930
939
  this.$$setUpdateOnEvents();
931
- },
940
+ }
932
941
 
933
942
  /**
934
943
  * @ngdoc method
@@ -1051,7 +1060,7 @@ NgModelController.prototype = {
1051
1060
  // It is possible that model and view value have been updated during render
1052
1061
  this.$$runValidators(this.$modelValue, this.$viewValue, () => {});
1053
1062
  }
1054
- },
1063
+ }
1055
1064
 
1056
1065
  /**
1057
1066
  * This method is called internally to run the $formatters on the $modelValue
@@ -1066,7 +1075,7 @@ NgModelController.prototype = {
1066
1075
  }
1067
1076
 
1068
1077
  return viewValue;
1069
- },
1078
+ }
1070
1079
 
1071
1080
  /**
1072
1081
  * This method is called internally when the bound scope value changes.
@@ -1075,23 +1084,25 @@ NgModelController.prototype = {
1075
1084
  this.$modelValue = this.$$rawModelValue = modelValue;
1076
1085
  this.$$parserValid = undefined;
1077
1086
  this.$processModelValue();
1078
- },
1087
+ }
1079
1088
 
1080
1089
  $$setUpdateOnEvents() {
1081
1090
  if (this.$$updateEvents) {
1082
1091
  this.$$element.off(this.$$updateEvents, this.$$updateEventHandler);
1083
1092
  }
1084
1093
 
1085
- this.$$updateEvents = this.$options.getOption("updateOn");
1094
+ this.$$updateEvents = /** @type {string} */ (
1095
+ this.$options.getOption("updateOn")
1096
+ );
1086
1097
  if (this.$$updateEvents) {
1087
1098
  this.$$element.on(this.$$updateEvents, this.$$updateEventHandler);
1088
1099
  }
1089
- },
1100
+ }
1090
1101
 
1091
1102
  $$updateEventHandler(ev) {
1092
1103
  this.$$debounceViewValueCommit(ev && ev.type);
1093
- },
1094
- };
1104
+ }
1105
+ }
1095
1106
 
1096
1107
  function setupModelWatcher(ctrl) {
1097
1108
  // model -> value
@@ -1121,229 +1132,8 @@ function setupModelWatcher(ctrl) {
1121
1132
  });
1122
1133
  }
1123
1134
 
1124
- /**
1125
- * @ngdoc method
1126
- * @name ngModel.NgModelController#$setValidity
1127
- *
1128
- * @description
1129
- * Change the validity state, and notify the form.
1130
- *
1131
- * This method can be called within $parsers/$formatters or a custom validation implementation.
1132
- * However, in most cases it should be sufficient to use the `ngModel.$validators` and
1133
- * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
1134
- *
1135
- * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
1136
- * to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
1137
- * (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
1138
- * The `validationErrorKey` should be in camelCase and will get converted into dash-case
1139
- * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
1140
- * classes and can be bound to as `{{ someForm.someControl.$error.myError }}`.
1141
- * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
1142
- * or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
1143
- * Skipped is used by AngularJS when validators do not run because of parse errors and
1144
- * when `$asyncValidators` do not run because any of the `$validators` failed.
1145
- */
1146
- addSetValidityMethod({
1147
- clazz: NgModelController,
1148
- set(object, property) {
1149
- object[property] = true;
1150
- },
1151
- unset(object, property) {
1152
- delete object[property];
1153
- },
1154
- });
1155
-
1156
- /**
1157
- * @ngdoc directive
1158
- * @name ngModel
1159
- * @restrict A
1160
- * @priority 1
1161
- * @param {string} ngModel assignable {@link guide/expression Expression} to bind to.
1162
- *
1163
- * @description
1164
- * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
1165
- * property on the scope using {@link ngModel.NgModelController NgModelController},
1166
- * which is created and exposed by this directive.
1167
- *
1168
- * `ngModel` is responsible for:
1169
- *
1170
- * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
1171
- * require.
1172
- * - Providing validation behavior (i.e. required, number, email, url).
1173
- * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
1174
- * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
1175
- * `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
1176
- * - Registering the control with its parent {@link ng.directive:form form}.
1177
- *
1178
- * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
1179
- * current scope. If the property doesn't already exist on this scope, it will be created
1180
- * implicitly and added to the scope.
1181
- *
1182
- * For best practices on using `ngModel`, see:
1183
- *
1184
- * - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
1185
- *
1186
- * For basic examples, how to use `ngModel`, see:
1187
- *
1188
- * - {@link ng.directive:input input}
1189
- * - {@link input[text] text}
1190
- * - {@link input[checkbox] checkbox}
1191
- * - {@link input[radio] radio}
1192
- * - {@link input[number] number}
1193
- * - {@link input[email] email}
1194
- * - {@link input[url] url}
1195
- * - {@link input[date] date}
1196
- * - {@link input[datetime-local] datetime-local}
1197
- * - {@link input[time] time}
1198
- * - {@link input[month] month}
1199
- * - {@link input[week] week}
1200
- * - {@link ng.directive:select select}
1201
- * - {@link ng.directive:textarea textarea}
1202
- *
1203
- * ## Complex Models (objects or collections)
1204
- *
1205
- * By default, `ngModel` watches the model by reference, not value. This is important to know when
1206
- * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
1207
- * object or collection change, `ngModel` will not be notified and so the input will not be re-rendered.
1208
- *
1209
- * The model must be assigned an entirely new object or collection before a re-rendering will occur.
1210
- *
1211
- * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
1212
- * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
1213
- * if the select is given the `multiple` attribute.
1214
- *
1215
- * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
1216
- * first level of the object (or only changing the properties of an item in the collection if it's an array) will still
1217
- * not trigger a re-rendering of the model.
1218
- *
1219
- * ## CSS classes
1220
- * The following CSS classes are added and removed on the associated input/select/textarea element
1221
- * depending on the validity of the model.
1222
- *
1223
- * - `ng-valid`: the model is valid
1224
- * - `ng-invalid`: the model is invalid
1225
- * - `ng-valid-[key]`: for each valid key added by `$setValidity`
1226
- * - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
1227
- * - `ng-pristine`: the control hasn't been interacted with yet
1228
- * - `ng-dirty`: the control has been interacted with
1229
- * - `ng-touched`: the control has been blurred
1230
- * - `ng-untouched`: the control hasn't been blurred
1231
- * - `ng-pending`: any `$asyncValidators` are unfulfilled
1232
- * - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
1233
- * by the {@link ngModel.NgModelController#$isEmpty} method
1234
- * - `ng-not-empty`: the view contains a non-empty value
1235
- *
1236
- * Keep in mind that ngAnimate can detect each of these classes when added and removed.
1237
- *
1238
- * @animations
1239
- * Animations within models are triggered when any of the associated CSS classes are added and removed
1240
- * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
1241
- * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
1242
- * The animations that are triggered within ngModel are similar to how they work in ngClass and
1243
- * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
1244
- *
1245
- * The following example shows a simple way to utilize CSS transitions to style an input element
1246
- * that has been rendered as invalid after it has been validated:
1247
- *
1248
- * <pre>
1249
- * //be sure to include ngAnimate as a module to hook into more
1250
- * //advanced animations
1251
- * .my-input {
1252
- * transition:0.5s linear all;
1253
- * background: white;
1254
- * }
1255
- * .my-input.ng-invalid {
1256
- * background: red;
1257
- * color:white;
1258
- * }
1259
- * </pre>
1260
- *
1261
- * @example
1262
- * ### Basic Usage
1263
- * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample" name="ng-model">
1264
- <file name="index.html">
1265
- <script>
1266
- angular.module('inputExample', [])
1267
- .controller('ExampleController', ['$scope', function($scope) {
1268
- $scope.val = '1';
1269
- }]);
1270
- </script>
1271
- <style>
1272
- .my-input {
1273
- transition:all linear 0.5s;
1274
- background: transparent;
1275
- }
1276
- .my-input.ng-invalid {
1277
- color:white;
1278
- background: red;
1279
- }
1280
- </style>
1281
- <p id="inputDescription">
1282
- Update input to see transitions when valid/invalid.
1283
- Integer is a valid value.
1284
- </p>
1285
- <form name="testForm" ng-controller="ExampleController">
1286
- <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
1287
- aria-describedby="inputDescription" />
1288
- </form>
1289
- </file>
1290
- * </example>
1291
- *
1292
- * @example
1293
- * ### Binding to a getter/setter
1294
- *
1295
- * Sometimes it's helpful to bind `ngModel` to a getter/setter function. A getter/setter is a
1296
- * function that returns a representation of the model when called with zero arguments, and sets
1297
- * the internal state of a model when called with an argument. It's sometimes useful to use this
1298
- * for models that have an internal representation that's different from what the model exposes
1299
- * to the view.
1300
- *
1301
- * <div class="alert alert-success">
1302
- * **Best Practice:** It's best to keep getters fast because AngularJS is likely to call them more
1303
- * frequently than other parts of your code.
1304
- * </div>
1305
- *
1306
- * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
1307
- * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
1308
- * a `<form>`, which will enable this behavior for all `<input>`s within it. See
1309
- * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
1310
- *
1311
- * The following example shows how to use `ngModel` with a getter/setter:
1312
- *
1313
- * @example
1314
- * <example name="ngModel-getter-setter" module="getterSetterExample">
1315
- <file name="index.html">
1316
- <div ng-controller="ExampleController">
1317
- <form name="userForm">
1318
- <label>Name:
1319
- <input type="text" name="userName"
1320
- ng-model="user.name"
1321
- ng-model-options="{ getterSetter: true }" />
1322
- </label>
1323
- </form>
1324
- <pre>user.name = <span ng-bind="user.name()"></span></pre>
1325
- </div>
1326
- </file>
1327
- <file name="app.js">
1328
- angular.module('getterSetterExample', [])
1329
- .controller('ExampleController', ['$scope', function($scope) {
1330
- let _name = 'Brian';
1331
- $scope.user = {
1332
- name: function(newName) {
1333
- // Note that newName can be undefined for two reasons:
1334
- // 1. Because it is called as a getter and thus called with no arguments
1335
- // 2. Because the property should actually be set to undefined. This happens e.g. if the
1336
- // input is invalid
1337
- return arguments.length ? (_name = newName) : _name;
1338
- }
1339
- };
1340
- }]);
1341
- </file>
1342
- * </example>
1343
- */
1344
- export const ngModelDirective = [
1345
- "$rootScope",
1346
- ($rootScope) => ({
1135
+ export function ngModelDirective($rootScope) {
1136
+ return {
1347
1137
  restrict: "A",
1348
1138
  require: ["ngModel", "^?form", "^?ngModelOptions"],
1349
1139
  controller: NgModelController,
@@ -1356,7 +1146,7 @@ export const ngModelDirective = [
1356
1146
  element[0].classList.add(PRISTINE_CLASS, UNTOUCHED_CLASS, VALID_CLASS);
1357
1147
 
1358
1148
  return {
1359
- pre: function ngModelPreLink(scope, element, attr, ctrls) {
1149
+ pre: function (scope, element, attr, ctrls) {
1360
1150
  const modelCtrl = ctrls[0];
1361
1151
  const formCtrl = ctrls[1] || modelCtrl.$$parentForm;
1362
1152
  const optionsCtrl = ctrls[2];
@@ -1400,5 +1190,5 @@ export const ngModelDirective = [
1400
1190
  },
1401
1191
  };
1402
1192
  },
1403
- }),
1404
- ];
1193
+ };
1194
+ }