@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.
- package/dist/angular-ts.esm.js +2 -2
- package/dist/angular-ts.umd.js +2 -2
- package/package.json +1 -1
- package/src/animations/animate-js.html +5 -2
- package/src/animations/animate-queue.js +1 -1
- package/src/animations/animate.js +0 -18
- package/src/core/compile/attributes.js +8 -1
- package/src/core/compile/compile.spec.js +0 -1
- package/src/core/controller/controller.js +9 -3
- package/src/core/q/q.js +2 -1
- package/src/directive/change/change.js +3 -1
- package/src/directive/form/form.js +4 -3
- package/src/directive/list/list.js +3 -3
- package/src/directive/messages/messages.js +177 -172
- package/src/directive/model/model.js +261 -471
- package/src/directive/switch/switch.js +4 -4
- package/src/router/directives/state-directives.js +2 -9
- package/src/router/hooks/core-resolvables.js +5 -3
- package/src/router/path/path-utils.js +1 -2
- package/src/router/resolve/resolve-context.js +14 -29
- package/src/router/state/state-queue-manager.js +1 -2
- package/src/router/state/state-service.js +2 -3
- package/src/router/transition/transition.js +2 -2
- package/src/router/view/view.js +2 -8
- package/src/shared/common.js +3 -8
- package/src/shared/common.spec.js +1 -19
- package/src/shared/hof.js +1 -8
- package/src/shared/jqlite/jqlite.js +1 -1
- package/src/shared/predicates.js +3 -2
- package/src/types.js +2 -3
- package/types/animations/animate-queue.d.ts +1 -1
- package/types/core/compile/attributes.d.ts +10 -1
- package/types/core/q/q.d.ts +4 -2
- package/types/directive/form/form.d.ts +3 -1
- package/types/directive/messages/messages.d.ts +76 -0
- package/types/directive/model/model.d.ts +101 -239
- package/types/router/resolve/resolve-context.d.ts +0 -2
- package/types/router/transition/transition.d.ts +0 -1
- package/types/shared/common.d.ts +0 -3
- package/types/shared/hof.d.ts +0 -1
- package/types/shared/jqlite/jqlite.d.ts +2 -2
- 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
|
-
|
|
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
|
-
*
|
|
33
|
-
* @
|
|
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
|
|
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,
|
|
107
|
-
*
|
|
108
|
-
*
|
|
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
|
-
*
|
|
116
|
-
*
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
|
265
|
-
const invokeModelSetter = this.$$parse(`${this.$$attr
|
|
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
|
|
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(
|
|
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
|
|
876
|
-
this.$options.getOption("updateOn").indexOf(
|
|
882
|
+
isNumber(debounceDelay["default"]) &&
|
|
883
|
+
/** @type {string} */ (this.$options.getOption("updateOn")).indexOf(
|
|
884
|
+
trigger,
|
|
885
|
+
) === -1
|
|
877
886
|
) {
|
|
878
|
-
debounceDelay = debounceDelay
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
+
}
|