@@ -384,11 +384,6 @@ var inputType = {
384384} ;
385385
386386
387- function isEmpty ( value ) {
388- return isUndefined ( value ) || value === '' || value === null || value !== value ;
389- }
390-
391-
392387function textInputType ( scope , element , attr , ctrl , $sniffer , $browser ) {
393388
394389 var listener = function ( ) {
@@ -445,7 +440,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
445440
446441
447442 ctrl . $render = function ( ) {
448- element . val ( isEmpty ( ctrl . $viewValue ) ? '' : ctrl . $viewValue ) ;
443+ element . val ( ctrl . $ isEmpty( ctrl . $viewValue ) ? '' : ctrl . $viewValue ) ;
449444 } ;
450445
451446 // pattern validator
@@ -454,7 +449,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
454449 match ;
455450
456451 var validate = function ( regexp , value ) {
457- if ( isEmpty ( value ) || regexp . test ( value ) ) {
452+ if ( ctrl . $ isEmpty( value ) || regexp . test ( value ) ) {
458453 ctrl . $setValidity ( 'pattern' , true ) ;
459454 return value ;
460455 } else {
@@ -468,7 +463,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
468463 if ( match ) {
469464 pattern = new RegExp ( match [ 1 ] , match [ 2 ] ) ;
470465 patternValidator = function ( value ) {
471- return validate ( pattern , value )
466+ return validate ( pattern , value ) ;
472467 } ;
473468 } else {
474469 patternValidator = function ( value ) {
@@ -491,7 +486,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
491486 if ( attr . ngMinlength ) {
492487 var minlength = int ( attr . ngMinlength ) ;
493488 var minLengthValidator = function ( value ) {
494- if ( ! isEmpty ( value ) && value . length < minlength ) {
489+ if ( ! ctrl . $ isEmpty( value ) && value . length < minlength ) {
495490 ctrl . $setValidity ( 'minlength' , false ) ;
496491 return undefined ;
497492 } else {
@@ -508,7 +503,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
508503 if ( attr . ngMaxlength ) {
509504 var maxlength = int ( attr . ngMaxlength ) ;
510505 var maxLengthValidator = function ( value ) {
511- if ( ! isEmpty ( value ) && value . length > maxlength ) {
506+ if ( ! ctrl . $ isEmpty( value ) && value . length > maxlength ) {
512507 ctrl . $setValidity ( 'maxlength' , false ) ;
513508 return undefined ;
514509 } else {
@@ -526,7 +521,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
526521 textInputType ( scope , element , attr , ctrl , $sniffer , $browser ) ;
527522
528523 ctrl . $parsers . push ( function ( value ) {
529- var empty = isEmpty ( value ) ;
524+ var empty = ctrl . $ isEmpty( value ) ;
530525 if ( empty || NUMBER_REGEXP . test ( value ) ) {
531526 ctrl . $setValidity ( 'number' , true ) ;
532527 return value === '' ? null : ( empty ? value : parseFloat ( value ) ) ;
@@ -537,13 +532,13 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
537532 } ) ;
538533
539534 ctrl . $formatters . push ( function ( value ) {
540- return isEmpty ( value ) ? '' : '' + value ;
535+ return ctrl . $ isEmpty( value ) ? '' : '' + value ;
541536 } ) ;
542537
543538 if ( attr . min ) {
544539 var min = parseFloat ( attr . min ) ;
545540 var minValidator = function ( value ) {
546- if ( ! isEmpty ( value ) && value < min ) {
541+ if ( ! ctrl . $ isEmpty( value ) && value < min ) {
547542 ctrl . $setValidity ( 'min' , false ) ;
548543 return undefined ;
549544 } else {
@@ -559,7 +554,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
559554 if ( attr . max ) {
560555 var max = parseFloat ( attr . max ) ;
561556 var maxValidator = function ( value ) {
562- if ( ! isEmpty ( value ) && value > max ) {
557+ if ( ! ctrl . $ isEmpty( value ) && value > max ) {
563558 ctrl . $setValidity ( 'max' , false ) ;
564559 return undefined ;
565560 } else {
@@ -574,7 +569,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
574569
575570 ctrl . $formatters . push ( function ( value ) {
576571
577- if ( isEmpty ( value ) || isNumber ( value ) ) {
572+ if ( ctrl . $ isEmpty( value ) || isNumber ( value ) ) {
578573 ctrl . $setValidity ( 'number' , true ) ;
579574 return value ;
580575 } else {
@@ -588,7 +583,7 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
588583 textInputType ( scope , element , attr , ctrl , $sniffer , $browser ) ;
589584
590585 var urlValidator = function ( value ) {
591- if ( isEmpty ( value ) || URL_REGEXP . test ( value ) ) {
586+ if ( ctrl . $ isEmpty( value ) || URL_REGEXP . test ( value ) ) {
592587 ctrl . $setValidity ( 'url' , true ) ;
593588 return value ;
594589 } else {
@@ -605,7 +600,7 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
605600 textInputType ( scope , element , attr , ctrl , $sniffer , $browser ) ;
606601
607602 var emailValidator = function ( value ) {
608- if ( isEmpty ( value ) || EMAIL_REGEXP . test ( value ) ) {
603+ if ( ctrl . $ isEmpty( value ) || EMAIL_REGEXP . test ( value ) ) {
609604 ctrl . $setValidity ( 'email' , true ) ;
610605 return value ;
611606 } else {
@@ -657,6 +652,11 @@ function checkboxInputType(scope, element, attr, ctrl) {
657652 element [ 0 ] . checked = ctrl . $viewValue ;
658653 } ;
659654
655+ // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
656+ ctrl . $isEmpty = function ( value ) {
657+ return value !== trueValue ;
658+ } ;
659+
660660 ctrl . $formatters . push ( function ( value ) {
661661 return value === trueValue ;
662662 } ) ;
@@ -992,6 +992,25 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
992992 */
993993 this . $render = noop ;
994994
995+ /**
996+ * @ngdoc function
997+ * @name { ng.directive:ngModel.NgModelController#$isEmpty
998+ * @methodOf ng.directive:ngModel.NgModelController
999+ *
1000+ * @description
1001+ * This is called when we need to determine if the value of the input is empty.
1002+ *
1003+ * For instance, the required directive does this to work out if the input has data or not.
1004+ * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
1005+ *
1006+ * You can override this for input directives whose concept of being empty is different to the
1007+ * default. The `checkboxInputType` directive does this because in its case a value of `false`
1008+ * implies empty.
1009+ */
1010+ this . $isEmpty = function ( value ) {
1011+ return isUndefined ( value ) || value === '' || value === null || value !== value ;
1012+ } ;
1013+
9951014 var parentForm = $element . inheritedData ( '$formController' ) || nullFormCtrl ,
9961015 invalidCount = 0 , // used to easily determine if we are valid
9971016 $error = this . $error = { } ; // keep invalid keys here
@@ -1266,7 +1285,7 @@ var requiredDirective = function() {
12661285 attr . required = true ; // force truthy in case we are on non input element
12671286
12681287 var validator = function ( value ) {
1269- if ( attr . required && ( isEmpty ( value ) || value === false ) ) {
1288+ if ( attr . required && ctrl . $ isEmpty( value ) ) {
12701289 ctrl . $setValidity ( 'required' , false ) ;
12711290 return ;
12721291 } else {
@@ -1327,7 +1346,7 @@ var requiredDirective = function() {
13271346
13281347 it('should be invalid if empty', function() {
13291348 input('names').enter('');
1330- expect(binding('names')).toEqual('[] ');
1349+ expect(binding('names')).toEqual('');
13311350 expect(binding('myForm.namesInput.$valid')).toEqual('false');
13321351 expect(element('span.error').css('display')).not().toBe('none');
13331352 });
@@ -1342,6 +1361,9 @@ var ngListDirective = function() {
13421361 separator = match && new RegExp ( match [ 1 ] ) || attr . ngList || ',' ;
13431362
13441363 var parse = function ( viewValue ) {
1364+ // If the viewValue is invalid (say required but empty) it will be `undefined`
1365+ if ( isUndefined ( viewValue ) ) return ;
1366+
13451367 var list = [ ] ;
13461368
13471369 if ( viewValue ) {
@@ -1361,6 +1383,11 @@ var ngListDirective = function() {
13611383
13621384 return undefined ;
13631385 } ) ;
1386+
1387+ // Override the standard $isEmpty because an empty array means the input is empty.
1388+ ctrl . $isEmpty = function ( value ) {
1389+ return ! value || ! value . length ;
1390+ } ;
13641391 }
13651392 } ;
13661393} ;
0 commit comments