@@ -862,15 +862,29 @@ function validate(ctrl, validatorName, validity, value){
862
862
return validity ? value : undefined ;
863
863
}
864
864
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
+ }
865
877
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 ) {
868
880
if ( isObject ( validity ) ) {
881
+ ctrl . $$hasNativeValidators = true ;
869
882
var validator = function ( value ) {
870
883
// Don't overwrite previous validation, don't consider valueMissing to apply (ng-required can
871
884
// 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 ) ) {
874
888
ctrl . $setValidity ( validatorName , false ) ;
875
889
return ;
876
890
}
@@ -881,8 +895,9 @@ function addNativeHtml5Validators(ctrl, validatorName, element) {
881
895
}
882
896
883
897
function textInputType ( scope , element , attr , ctrl , $sniffer , $browser ) {
884
- var validity = element . prop ( 'validity' ) ;
898
+ var validity = element . prop ( VALIDITY_STATE_PROPERTY ) ;
885
899
var placeholder = element [ 0 ] . placeholder , noevent = { } ;
900
+ ctrl . $$validityState = validity ;
886
901
887
902
// In composition mode, users are still inputing intermediate text buffer,
888
903
// hold the listener until composition is done.
@@ -921,16 +936,16 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
921
936
value = trim ( value ) ;
922
937
}
923
938
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 ) ) {
929
944
if ( scope . $$phase ) {
930
- ctrl . $setViewValue ( value , event ) ;
945
+ ctrl . $setViewValue ( value , event , revalidate ) ;
931
946
} else {
932
947
scope . $apply ( function ( ) {
933
- ctrl . $setViewValue ( value , event ) ;
948
+ ctrl . $setViewValue ( value , event , revalidate ) ;
934
949
} ) ;
935
950
}
936
951
}
@@ -1079,6 +1094,8 @@ function createDateInputType(type, regexp, parseDate, format) {
1079
1094
} ;
1080
1095
}
1081
1096
1097
+ var numberBadFlags = [ 'badInput' ] ;
1098
+
1082
1099
function numberInputType ( scope , element , attr , ctrl , $sniffer , $browser ) {
1083
1100
textInputType ( scope , element , attr , ctrl , $sniffer , $browser ) ;
1084
1101
@@ -1093,7 +1110,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
1093
1110
}
1094
1111
} ) ;
1095
1112
1096
- addNativeHtml5Validators ( ctrl , 'number' , element ) ;
1113
+ addNativeHtml5Validators ( ctrl , 'number' , numberBadFlags , null , ctrl . $$validityState ) ;
1097
1114
1098
1115
ctrl . $formatters . push ( function ( value ) {
1099
1116
return ctrl . $isEmpty ( value ) ? '' : '' + value ;
@@ -1773,11 +1790,11 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1773
1790
* event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
1774
1791
* usually handles calling this in response to input events.
1775
1792
*/
1776
- this . $commitViewValue = function ( ) {
1793
+ this . $commitViewValue = function ( revalidate ) {
1777
1794
var viewValue = ctrl . $viewValue ;
1778
1795
1779
1796
$timeout . cancel ( pendingDebounce ) ;
1780
- if ( ctrl . $$lastCommittedViewValue === viewValue ) {
1797
+ if ( ! revalidate && ctrl . $$lastCommittedViewValue === viewValue ) {
1781
1798
return ;
1782
1799
}
1783
1800
ctrl . $$lastCommittedViewValue = viewValue ;
@@ -1842,14 +1859,14 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1842
1859
* @param {string } value Value from the view.
1843
1860
* @param {string } trigger Event that triggered the update.
1844
1861
*/
1845
- this . $setViewValue = function ( value , trigger ) {
1862
+ this . $setViewValue = function ( value , trigger , revalidate ) {
1846
1863
ctrl . $viewValue = value ;
1847
1864
if ( ! ctrl . $options || ctrl . $options . updateOnDefault ) {
1848
- ctrl . $$debounceViewValueCommit ( trigger ) ;
1865
+ ctrl . $$debounceViewValueCommit ( trigger , revalidate ) ;
1849
1866
}
1850
1867
} ;
1851
1868
1852
- this . $$debounceViewValueCommit = function ( trigger ) {
1869
+ this . $$debounceViewValueCommit = function ( trigger , revalidate ) {
1853
1870
var debounceDelay = 0 ,
1854
1871
options = ctrl . $options ,
1855
1872
debounce ;
@@ -1868,10 +1885,10 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1868
1885
$timeout . cancel ( pendingDebounce ) ;
1869
1886
if ( debounceDelay ) {
1870
1887
pendingDebounce = $timeout ( function ( ) {
1871
- ctrl . $commitViewValue ( ) ;
1888
+ ctrl . $commitViewValue ( revalidate ) ;
1872
1889
} , debounceDelay ) ;
1873
1890
} else {
1874
- ctrl . $commitViewValue ( ) ;
1891
+ ctrl . $commitViewValue ( revalidate ) ;
1875
1892
}
1876
1893
} ;
1877
1894
0 commit comments