6
6
DIRTY_CLASS: true,
7
7
UNTOUCHED_CLASS: true,
8
8
TOUCHED_CLASS: true,
9
+ $ModelOptionsProvider: true,
9
10
*/
10
11
11
12
var VALID_CLASS = 'ng-valid' ,
@@ -217,8 +218,8 @@ is set to `true`. The parse error is stored in `ngModel.$error.parse`.
217
218
*
218
219
*
219
220
*/
220
- var NgModelController = [ '$scope' , '$exceptionHandler' , '$attrs' , '$element' , '$parse' , '$animate' , '$timeout' , '$rootScope' , '$q' , '$interpolate' ,
221
- function ( $scope , $exceptionHandler , $attr , $element , $parse , $animate , $timeout , $rootScope , $q , $interpolate ) {
221
+ var NgModelController = [ '$scope' , '$exceptionHandler' , '$attrs' , '$element' , '$parse' , '$animate' , '$timeout' , '$rootScope' , '$q' , '$interpolate' , '$modelOptions' ,
222
+ function ( $scope , $exceptionHandler , $attr , $element , $parse , $animate , $timeout , $rootScope , $q , $interpolate , $modelOptions ) {
222
223
this . $viewValue = Number . NaN ;
223
224
this . $modelValue = Number . NaN ;
224
225
this . $$rawModelValue = undefined ; // stores the parsed modelValue / model set from scope regardless of validity.
@@ -237,7 +238,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
237
238
this . $$success = { } ; // keep valid keys here
238
239
this . $pending = undefined ; // keep pending keys here
239
240
this . $name = $interpolate ( $attr . name || '' , false ) ( $scope ) ;
240
-
241
+ this . $options = $modelOptions . defaultOptions ;
241
242
242
243
var parsedNgModel = $parse ( $attr . ngModel ) ,
243
244
parsedNgModelAssign = parsedNgModel . assign ,
@@ -246,9 +247,10 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
246
247
pendingDebounce = null ,
247
248
ctrl = this ;
248
249
249
- this . $$setOptions = function ( options ) {
250
- ctrl . $options = options ;
251
- if ( options && options . getterSetter ) {
250
+
251
+ this . $$initGetterSetters = function ( ) {
252
+
253
+ if ( ctrl . $options . getterSetter ) {
252
254
var invokeModelGetter = $parse ( $attr . ngModel + '()' ) ,
253
255
invokeModelSetter = $parse ( $attr . ngModel + '($$$p)' ) ;
254
256
@@ -272,6 +274,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
272
274
}
273
275
} ;
274
276
277
+
275
278
/**
276
279
* @ngdoc method
277
280
* @name ngModel.NgModelController#$render
@@ -523,7 +526,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
523
526
var prevValid = ctrl . $valid ;
524
527
var prevModelValue = ctrl . $modelValue ;
525
528
526
- var allowInvalid = ctrl . $options && ctrl . $options . allowInvalid ;
529
+ var allowInvalid = ctrl . $options . allowInvalid ;
527
530
528
531
ctrl . $$runValidators ( parserValid , modelValue , viewValue , function ( allValid ) {
529
532
// If there was no change in validity, don't update the model
@@ -683,7 +686,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
683
686
ctrl . $modelValue = ngModelGet ( $scope ) ;
684
687
}
685
688
var prevModelValue = ctrl . $modelValue ;
686
- var allowInvalid = ctrl . $options && ctrl . $options . allowInvalid ;
689
+ var allowInvalid = ctrl . $options . allowInvalid ;
687
690
ctrl . $$rawModelValue = modelValue ;
688
691
689
692
if ( allowInvalid ) {
@@ -764,25 +767,19 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
764
767
*/
765
768
this . $setViewValue = function ( value , trigger ) {
766
769
ctrl . $viewValue = value ;
767
- if ( ! ctrl . $options || ctrl . $options . updateOnDefault ) {
770
+ if ( ctrl . $options . updateOnDefault ) {
768
771
ctrl . $$debounceViewValueCommit ( trigger ) ;
769
772
}
770
773
} ;
771
774
772
775
this . $$debounceViewValueCommit = function ( trigger ) {
773
- var debounceDelay = 0 ,
774
- options = ctrl . $options ,
775
- debounce ;
776
-
777
- if ( options && isDefined ( options . debounce ) ) {
778
- debounce = options . debounce ;
779
- if ( isNumber ( debounce ) ) {
780
- debounceDelay = debounce ;
781
- } else if ( isNumber ( debounce [ trigger ] ) ) {
782
- debounceDelay = debounce [ trigger ] ;
783
- } else if ( isNumber ( debounce [ 'default' ] ) ) {
784
- debounceDelay = debounce [ 'default' ] ;
785
- }
776
+ var options = ctrl . $options ,
777
+ debounceDelay = options . debounce ;
778
+
779
+ if ( isNumber ( debounceDelay [ trigger ] ) ) {
780
+ debounceDelay = debounceDelay [ trigger ] ;
781
+ } else if ( isNumber ( debounceDelay [ 'default' ] ) ) {
782
+ debounceDelay = debounceDelay [ 'default' ] ;
786
783
}
787
784
788
785
$timeout . cancel ( pendingDebounce ) ;
@@ -1014,9 +1011,14 @@ var ngModelDirective = ['$rootScope', function($rootScope) {
1014
1011
return {
1015
1012
pre : function ngModelPreLink ( scope , element , attr , ctrls ) {
1016
1013
var modelCtrl = ctrls [ 0 ] ,
1017
- formCtrl = ctrls [ 1 ] || nullFormCtrl ;
1014
+ formCtrl = ctrls [ 1 ] || nullFormCtrl ,
1015
+ optionsCtrl = ctrls [ 2 ] ;
1018
1016
1019
- modelCtrl . $$setOptions ( ctrls [ 2 ] && ctrls [ 2 ] . $options ) ;
1017
+ if ( optionsCtrl ) {
1018
+ modelCtrl . $options = optionsCtrl . $options ;
1019
+ }
1020
+
1021
+ modelCtrl . $$initGetterSetters ( ) ;
1020
1022
1021
1023
// notify others, especially parent forms
1022
1024
formCtrl . $addControl ( modelCtrl ) ;
@@ -1033,7 +1035,7 @@ var ngModelDirective = ['$rootScope', function($rootScope) {
1033
1035
} ,
1034
1036
post : function ngModelPostLink ( scope , element , attr , ctrls ) {
1035
1037
var modelCtrl = ctrls [ 0 ] ;
1036
- if ( modelCtrl . $options && modelCtrl . $options . updateOn ) {
1038
+ if ( modelCtrl . $options . updateOn ) {
1037
1039
element . on ( modelCtrl . $options . updateOn , function ( ev ) {
1038
1040
modelCtrl . $$debounceViewValueCommit ( ev && ev . type ) ;
1039
1041
} ) ;
@@ -1075,9 +1077,10 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
1075
1077
*
1076
1078
* If a setting is not specified as a property on the object for a particular ngModelOptions directive
1077
1079
* then it will inherit that setting from the first ngModelOptions directive found by traversing up the
1078
- * DOM tree.
1080
+ * DOM tree. If there is no ancestor element containing an ngModelOptions directive then the settings in
1081
+ * {@link $modelOptions `$modelOptions.defaultOptions`} will be used.
1079
1082
*
1080
- * For example in the following fragment of HTML ...
1083
+ * For example given the following fragment of HTML
1081
1084
*
1082
1085
*
1083
1086
* ```html
@@ -1088,7 +1091,7 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
1088
1091
* </div>
1089
1092
* ```
1090
1093
*
1091
- * ... the `input` element will effective have the following settings ...
1094
+ * the `input` element will have the following settings
1092
1095
*
1093
1096
* ```js
1094
1097
* { allowInvalid: true, updateOn: 'default' }
@@ -1205,7 +1208,7 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
1205
1208
* ## Connecting to the scope
1206
1209
*
1207
1210
* By setting the `getterSetter` property to true you are telling ngModel that the `ngModel` expression
1208
- * on the scope actually refers to a "getter/setter" function rather than the actual value itself.
1211
+ * on the scope refers to a "getter/setter" function rather than the value itself.
1209
1212
*
1210
1213
* The following example shows how to bind to getter/setters:
1211
1214
*
@@ -1256,7 +1259,7 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
1256
1259
* `<input type="date">`, `<input type="time">`, ... . Right now, the only supported value is `'UTC'`,
1257
1260
* otherwise the default timezone of the browser will be used.
1258
1261
*/
1259
- var ngModelOptionsDirective = function ( ) {
1262
+ var ngModelOptionsDirective = [ '$modelOptions' , function ( $modelOptions ) {
1260
1263
return {
1261
1264
restrict : 'A' ,
1262
1265
// ngModelOptions needs to run before ngModel and input directives
@@ -1266,10 +1269,10 @@ var ngModelOptionsDirective = function() {
1266
1269
link : {
1267
1270
pre : function ngModelOptionsPreLinkFn ( scope , element , attrs , ctrls ) {
1268
1271
var optionsCtrl = ctrls [ 0 ] ;
1269
- var parentOptions = ctrls [ 1 ] ? ctrls [ 1 ] . $localOptions : { } ;
1272
+ var parentOptions = ctrls [ 1 ] ? ctrls [ 1 ] . $localOptions : $modelOptions . defaultOptions ;
1270
1273
1271
1274
// Store the raw options taken from the attributes (after inheriting parent options)
1272
- optionsCtrl . $localOptions = extend ( { } , scope . $eval ( attrs . ngModelOptions ) , parentOptions ) ;
1275
+ optionsCtrl . $localOptions = extend ( { } , parentOptions , scope . $eval ( attrs . ngModelOptions ) ) ;
1273
1276
1274
1277
// Make a copy and manipulate the options to make them ready to be consumed
1275
1278
optionsCtrl . $options = copy ( optionsCtrl . $localOptions ) ;
@@ -1288,7 +1291,47 @@ var ngModelOptionsDirective = function() {
1288
1291
}
1289
1292
}
1290
1293
} ;
1291
- } ;
1294
+ } ] ;
1295
+
1296
+
1297
+ /**
1298
+ * @ngdoc service
1299
+ * @name $modelOptions
1300
+ * @description
1301
+ *
1302
+ * This service provides support to the {@link ngModelOptions} directive.
1303
+ *
1304
+ * Here, you can change the default settings from which {@link ngModelOptions}
1305
+ * directives inherit.
1306
+ *
1307
+ * See the {@link ngModelOptions} directive for a list of the available options.
1308
+ *
1309
+ */
1310
+ function $ModelOptionsProvider ( ) {
1311
+ return {
1312
+ $get : function ( ) {
1313
+ return {
1314
+ /**
1315
+ * @ngdoc property
1316
+ * @name $modelOptions#defaultOptions
1317
+ * @type {Object }
1318
+ * @description
1319
+ * The default options to fall back on when there are no more ngModelOption
1320
+ * directives as ancestors
1321
+ *
1322
+ * The initial default options are:
1323
+ *
1324
+ * * `updateOneDefault`: `true`
1325
+ * * `debounce`: `0`
1326
+ */
1327
+ defaultOptions : {
1328
+ updateOnDefault : true ,
1329
+ debounce : 0
1330
+ }
1331
+ } ;
1332
+ }
1333
+ } ;
1334
+ }
1292
1335
1293
1336
1294
1337
0 commit comments