@@ -862,15 +862,29 @@ function validate(ctrl, validatorName, validity, value){
862862  return  validity  ? value  : undefined ; 
863863} 
864864
865+ function  testFlags ( validity ,  flags )  { 
866+   var  i ,  flag ; 
867+   if  ( flags )  { 
868+     for  ( i = 0 ;  i < flags . length ;  ++ i )  { 
869+       flag  =  flags [ i ] ; 
870+       if  ( validity [ flag ] )  { 
871+         return  true ; 
872+       } 
873+     } 
874+   } 
875+   return  false ; 
876+ } 
865877
866- function   addNativeHtml5Validators ( ctrl ,   validatorName ,   element )   { 
867-    var   validity   =   element . prop ( ' validity' ) ; 
878+ // Pass validity so that behaviour can be mocked easier. 
879+ function   addNativeHtml5Validators ( ctrl ,   validatorName ,   badFlags ,   ignoreFlags ,   validity )   { 
868880  if  ( isObject ( validity ) )  { 
881+     ctrl . $$hasNativeValidators  =  true ; 
869882    var  validator  =  function ( value )  { 
870883      // Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can 
871884      // perform the required validation) 
872-       if  ( ! ctrl . $error [ validatorName ]  &&  ( validity . badInput  ||  validity . customError  || 
873-           validity . typeMismatch )  &&  ! validity . valueMissing )  { 
885+       if  ( ! ctrl . $error [ validatorName ]  && 
886+           ! testFlags ( validity ,  ignoreFlags )  && 
887+           testFlags ( validity ,  badFlags ) )  { 
874888        ctrl . $setValidity ( validatorName ,  false ) ; 
875889        return ; 
876890      } 
@@ -881,8 +895,9 @@ function addNativeHtml5Validators(ctrl, validatorName, element) {
881895} 
882896
883897function  textInputType ( scope ,  element ,  attr ,  ctrl ,  $sniffer ,  $browser )  { 
884-   var  validity  =  element . prop ( 'validity' ) ; 
898+   var  validity  =  element . prop ( VALIDITY_STATE_PROPERTY ) ; 
885899  var  placeholder  =  element [ 0 ] . placeholder ,  noevent  =  { } ; 
900+   ctrl . $$validityState  =  validity ; 
886901
887902  // In composition mode, users are still inputing intermediate text buffer, 
888903  // hold the listener until composition is done. 
@@ -921,16 +936,16 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
921936      value  =  trim ( value ) ; 
922937    } 
923938
924-     if   ( ctrl . $viewValue   !==   value   || 
925-          // If the value is still empty/falsy, and there  is no `required` error, run validators  
926-          // again. This enables HTML5 constraint validation errors to affect Angular validation  
927-          // even when the first character entered causes an error. 
928-          ( validity   &&   value  ===  ''  &&  ! validity . valueMissing ) )  { 
939+     // If a control is suffering from bad input, browsers discard its  value, so it may be 
940+     // necessary to revalidate even if the control's value  is the same empty value twice in  
941+     // a row.  
942+     var   revalidate   =   validity   &&   ctrl . $$hasNativeValidators ; 
943+     if   ( ctrl . $viewValue   !==   value   ||   ( value  ===  ''  &&  revalidate ) )  { 
929944      if  ( scope . $$phase )  { 
930-         ctrl . $setViewValue ( value ,  event ) ; 
945+         ctrl . $setViewValue ( value ,  event ,   revalidate ) ; 
931946      }  else  { 
932947        scope . $apply ( function ( )  { 
933-           ctrl . $setViewValue ( value ,  event ) ; 
948+           ctrl . $setViewValue ( value ,  event ,   revalidate ) ; 
934949        } ) ; 
935950      } 
936951    } 
@@ -1079,6 +1094,8 @@ function createDateInputType(type, regexp, parseDate, format) {
10791094   } ; 
10801095} 
10811096
1097+ var  numberBadFlags  =  [ 'badInput' ] ; 
1098+ 
10821099function  numberInputType ( scope ,  element ,  attr ,  ctrl ,  $sniffer ,  $browser )  { 
10831100  textInputType ( scope ,  element ,  attr ,  ctrl ,  $sniffer ,  $browser ) ; 
10841101
@@ -1093,7 +1110,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
10931110    } 
10941111  } ) ; 
10951112
1096-   addNativeHtml5Validators ( ctrl ,  'number' ,  element ) ; 
1113+   addNativeHtml5Validators ( ctrl ,  'number' ,  numberBadFlags ,   null ,   ctrl . $$validityState ) ; 
10971114
10981115  ctrl . $formatters . push ( function ( value )  { 
10991116    return  ctrl . $isEmpty ( value )  ? ''  : ''  +  value ; 
@@ -1773,11 +1790,11 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
17731790   * event defined in `ng-model-options`. this method is rarely needed as `NgModelController` 
17741791   * usually handles calling this in response to input events. 
17751792   */ 
1776-   this . $commitViewValue  =  function ( )  { 
1793+   this . $commitViewValue  =  function ( revalidate )  { 
17771794    var  viewValue  =  ctrl . $viewValue ; 
17781795
17791796    $timeout . cancel ( pendingDebounce ) ; 
1780-     if  ( ctrl . $$lastCommittedViewValue  ===  viewValue )  { 
1797+     if  ( ! revalidate   &&   ctrl . $$lastCommittedViewValue  ===  viewValue )  { 
17811798      return ; 
17821799    } 
17831800    ctrl . $$lastCommittedViewValue  =  viewValue ; 
@@ -1842,14 +1859,14 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
18421859   * @param  {string } value Value from the view. 
18431860   * @param  {string } trigger Event that triggered the update. 
18441861   */ 
1845-   this . $setViewValue  =  function ( value ,  trigger )  { 
1862+   this . $setViewValue  =  function ( value ,  trigger ,   revalidate )  { 
18461863    ctrl . $viewValue  =  value ; 
18471864    if  ( ! ctrl . $options  ||  ctrl . $options . updateOnDefault )  { 
1848-       ctrl . $$debounceViewValueCommit ( trigger ) ; 
1865+       ctrl . $$debounceViewValueCommit ( trigger ,   revalidate ) ; 
18491866    } 
18501867  } ; 
18511868
1852-   this . $$debounceViewValueCommit  =  function ( trigger )  { 
1869+   this . $$debounceViewValueCommit  =  function ( trigger ,   revalidate )  { 
18531870    var  debounceDelay  =  0 , 
18541871        options  =  ctrl . $options , 
18551872        debounce ; 
@@ -1868,10 +1885,10 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
18681885    $timeout . cancel ( pendingDebounce ) ; 
18691886    if  ( debounceDelay )  { 
18701887      pendingDebounce  =  $timeout ( function ( )  { 
1871-         ctrl . $commitViewValue ( ) ; 
1888+         ctrl . $commitViewValue ( revalidate ) ; 
18721889      } ,  debounceDelay ) ; 
18731890    }  else  { 
1874-       ctrl . $commitViewValue ( ) ; 
1891+       ctrl . $commitViewValue ( revalidate ) ; 
18751892    } 
18761893  } ; 
18771894
0 commit comments