@@ -445,7 +445,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
445
445
446
446
447
447
ctrl . $render = function ( ) {
448
- element . val ( isEmpty ( ctrl . $viewValue ) ? '' : ctrl . $viewValue ) ;
448
+ element . val ( ctrl . $ isEmpty( ctrl . $viewValue ) ? '' : ctrl . $viewValue ) ;
449
449
} ;
450
450
451
451
// pattern validator
@@ -454,7 +454,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
454
454
match ;
455
455
456
456
var validate = function ( regexp , value ) {
457
- if ( isEmpty ( value ) || regexp . test ( value ) ) {
457
+ if ( ctrl . $ isEmpty( value ) || regexp . test ( value ) ) {
458
458
ctrl . $setValidity ( 'pattern' , true ) ;
459
459
return value ;
460
460
} else {
@@ -468,7 +468,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
468
468
if ( match ) {
469
469
pattern = new RegExp ( match [ 1 ] , match [ 2 ] ) ;
470
470
patternValidator = function ( value ) {
471
- return validate ( pattern , value )
471
+ return validate ( pattern , value ) ;
472
472
} ;
473
473
} else {
474
474
patternValidator = function ( value ) {
@@ -491,7 +491,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
491
491
if ( attr . ngMinlength ) {
492
492
var minlength = int ( attr . ngMinlength ) ;
493
493
var minLengthValidator = function ( value ) {
494
- if ( ! isEmpty ( value ) && value . length < minlength ) {
494
+ if ( ! ctrl . $ isEmpty( value ) && value . length < minlength ) {
495
495
ctrl . $setValidity ( 'minlength' , false ) ;
496
496
return undefined ;
497
497
} else {
@@ -508,7 +508,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
508
508
if ( attr . ngMaxlength ) {
509
509
var maxlength = int ( attr . ngMaxlength ) ;
510
510
var maxLengthValidator = function ( value ) {
511
- if ( ! isEmpty ( value ) && value . length > maxlength ) {
511
+ if ( ! ctrl . $ isEmpty( value ) && value . length > maxlength ) {
512
512
ctrl . $setValidity ( 'maxlength' , false ) ;
513
513
return undefined ;
514
514
} else {
@@ -526,7 +526,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
526
526
textInputType ( scope , element , attr , ctrl , $sniffer , $browser ) ;
527
527
528
528
ctrl . $parsers . push ( function ( value ) {
529
- var empty = isEmpty ( value ) ;
529
+ var empty = ctrl . $ isEmpty( value ) ;
530
530
if ( empty || NUMBER_REGEXP . test ( value ) ) {
531
531
ctrl . $setValidity ( 'number' , true ) ;
532
532
return value === '' ? null : ( empty ? value : parseFloat ( value ) ) ;
@@ -537,13 +537,13 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
537
537
} ) ;
538
538
539
539
ctrl . $formatters . push ( function ( value ) {
540
- return isEmpty ( value ) ? '' : '' + value ;
540
+ return ctrl . $ isEmpty( value ) ? '' : '' + value ;
541
541
} ) ;
542
542
543
543
if ( attr . min ) {
544
544
var min = parseFloat ( attr . min ) ;
545
545
var minValidator = function ( value ) {
546
- if ( ! isEmpty ( value ) && value < min ) {
546
+ if ( ! ctrl . $ isEmpty( value ) && value < min ) {
547
547
ctrl . $setValidity ( 'min' , false ) ;
548
548
return undefined ;
549
549
} else {
@@ -559,7 +559,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
559
559
if ( attr . max ) {
560
560
var max = parseFloat ( attr . max ) ;
561
561
var maxValidator = function ( value ) {
562
- if ( ! isEmpty ( value ) && value > max ) {
562
+ if ( ! ctrl . $ isEmpty( value ) && value > max ) {
563
563
ctrl . $setValidity ( 'max' , false ) ;
564
564
return undefined ;
565
565
} else {
@@ -574,7 +574,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
574
574
575
575
ctrl . $formatters . push ( function ( value ) {
576
576
577
- if ( isEmpty ( value ) || isNumber ( value ) ) {
577
+ if ( ctrl . $ isEmpty( value ) || isNumber ( value ) ) {
578
578
ctrl . $setValidity ( 'number' , true ) ;
579
579
return value ;
580
580
} else {
@@ -588,7 +588,7 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
588
588
textInputType ( scope , element , attr , ctrl , $sniffer , $browser ) ;
589
589
590
590
var urlValidator = function ( value ) {
591
- if ( isEmpty ( value ) || URL_REGEXP . test ( value ) ) {
591
+ if ( ctrl . $ isEmpty( value ) || URL_REGEXP . test ( value ) ) {
592
592
ctrl . $setValidity ( 'url' , true ) ;
593
593
return value ;
594
594
} else {
@@ -605,7 +605,7 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
605
605
textInputType ( scope , element , attr , ctrl , $sniffer , $browser ) ;
606
606
607
607
var emailValidator = function ( value ) {
608
- if ( isEmpty ( value ) || EMAIL_REGEXP . test ( value ) ) {
608
+ if ( ctrl . $ isEmpty( value ) || EMAIL_REGEXP . test ( value ) ) {
609
609
ctrl . $setValidity ( 'email' , true ) ;
610
610
return value ;
611
611
} else {
@@ -657,6 +657,12 @@ function checkboxInputType(scope, element, attr, ctrl) {
657
657
element [ 0 ] . checked = ctrl . $viewValue ;
658
658
} ;
659
659
660
+ // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
661
+ var _$isEmpty = ctrl . $isEmpty ;
662
+ ctrl . $isEmpty = function ( value ) {
663
+ return _$isEmpty ( value ) || value === false ;
664
+ } ;
665
+
660
666
ctrl . $formatters . push ( function ( value ) {
661
667
return value === trueValue ;
662
668
} ) ;
@@ -992,6 +998,23 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
992
998
*/
993
999
this . $render = noop ;
994
1000
1001
+ /**
1002
+ * @ngdoc function
1003
+ * @name { ng.directive:ngModel.NgModelController#$isEmpty
1004
+ * @methodOf ng.directive:ngModel.NgModelController
1005
+ *
1006
+ * @description
1007
+ * This is called when we need to determine if the value of the input is empty.
1008
+ *
1009
+ * For instance, the required directive does this to work out if the input has data or not.
1010
+ * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
1011
+ *
1012
+ * You can override this for input directives whose concept of being empty is different to the
1013
+ * default. The `checkboxInputType` directive does this because in its case a value of `false`
1014
+ * implies empty.
1015
+ */
1016
+ this . $isEmpty = isEmpty ;
1017
+
995
1018
var parentForm = $element . inheritedData ( '$formController' ) || nullFormCtrl ,
996
1019
invalidCount = 0 , // used to easily determine if we are valid
997
1020
$error = this . $error = { } ; // keep invalid keys here
@@ -1266,7 +1289,7 @@ var requiredDirective = function() {
1266
1289
attr . required = true ; // force truthy in case we are on non input element
1267
1290
1268
1291
var validator = function ( value ) {
1269
- if ( attr . required && ( isEmpty ( value ) || value === false ) ) {
1292
+ if ( attr . required && ctrl . $ isEmpty( value ) ) {
1270
1293
ctrl . $setValidity ( 'required' , false ) ;
1271
1294
return ;
1272
1295
} else {
@@ -1326,7 +1349,7 @@ var requiredDirective = function() {
1326
1349
1327
1350
it('should be invalid if empty', function() {
1328
1351
input('names').enter('');
1329
- expect(binding('names')).toEqual('[] ');
1352
+ expect(binding('names')).toEqual('');
1330
1353
expect(binding('myForm.namesInput.$valid')).toEqual('false');
1331
1354
expect(element('span.error').css('display')).not().toBe('none');
1332
1355
});
@@ -1341,6 +1364,9 @@ var ngListDirective = function() {
1341
1364
separator = match && new RegExp ( match [ 1 ] ) || attr . ngList || ',' ;
1342
1365
1343
1366
var parse = function ( viewValue ) {
1367
+ // If the viewValue is invalid (say required but empty) it will be `undefined`
1368
+ if ( isUndefined ( viewValue ) ) return ;
1369
+
1344
1370
var list = [ ] ;
1345
1371
1346
1372
if ( viewValue ) {
@@ -1360,6 +1386,12 @@ var ngListDirective = function() {
1360
1386
1361
1387
return undefined ;
1362
1388
} ) ;
1389
+
1390
+ // Override the standard $isEmpty because an empty array means the input is empty
1391
+ var _$isEmpty = ctrl . $isEmpty ;
1392
+ ctrl . $isEmpty = function ( value ) {
1393
+ return _$isEmpty ( value ) || value . length === 0 ;
1394
+ } ;
1363
1395
}
1364
1396
} ;
1365
1397
} ;
0 commit comments