@@ -1651,15 +1651,33 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1651
1651
this . $name = $attr . name ;
1652
1652
1653
1653
1654
- var ngModelGet = $parse ( $attr . ngModel ) ,
1655
- ngModelSet = ngModelGet . assign ,
1654
+ var parsedNgModel = $parse ( $attr . ngModel ) ,
1656
1655
pendingDebounce = null ,
1657
1656
ctrl = this ;
1658
1657
1658
+ var ngModelGet = function ngModelGet ( ) {
1659
+ var modelValue = parsedNgModel ( $scope ) ;
1660
+ if ( ctrl . $options && ctrl . $options . getterSetter && isFunction ( modelValue ) ) {
1661
+ modelValue = modelValue ( ) ;
1662
+ }
1663
+ return modelValue ;
1664
+ } ;
1665
+
1666
+ var ngModelSet = function ngModelSet ( newValue ) {
1667
+ var getterSetter ;
1668
+ if ( ctrl . $options && ctrl . $options . getterSetter &&
1669
+ isFunction ( getterSetter = parsedNgModel ( $scope ) ) ) {
1670
+
1671
+ getterSetter ( ctrl . $modelValue ) ;
1672
+ } else {
1673
+ parsedNgModel . assign ( $scope , ctrl . $modelValue ) ;
1674
+ }
1675
+ } ;
1676
+
1659
1677
this . $$setOptions = function ( options ) {
1660
1678
ctrl . $options = options ;
1661
1679
1662
- if ( ! ngModelSet && ( ! options || ! options . getterSetter ) ) {
1680
+ if ( ! parsedNgModel . assign && ( ! options || ! options . getterSetter ) ) {
1663
1681
throw $ngModelMinErr ( 'nonassign' , "Expression '{0}' is non-assignable. Element: {1}" ,
1664
1682
$attr . ngModel , startingTag ( $element ) ) ;
1665
1683
}
@@ -1875,26 +1893,17 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1875
1893
* Runs each of the registered validators (first synchronous validators and then asynchronous validators).
1876
1894
*/
1877
1895
this . $validate = function ( ) {
1878
- // ignore $validate before model initialized
1879
- if ( ctrl . $modelValue !== ctrl . $modelValue ) {
1896
+ // ignore $validate before model is initialized
1897
+ if ( isNumber ( ctrl . $modelValue ) && isNaN ( ctrl . $modelValue ) ) {
1880
1898
return ;
1881
1899
}
1882
-
1883
- var prev = ctrl . $modelValue ;
1884
- ctrl . $$runValidators ( undefined , ctrl . $$invalidModelValue || ctrl . $modelValue , ctrl . $viewValue , function ( ) {
1885
- if ( prev !== ctrl . $modelValue ) {
1886
- ctrl . $$writeModelToScope ( ) ;
1887
- }
1888
- } ) ;
1900
+ this . $$parseAndValidate ( ) ;
1889
1901
} ;
1890
1902
1891
1903
this . $$runValidators = function ( parseValid , modelValue , viewValue , doneCallback ) {
1892
1904
currentValidationRunId ++ ;
1893
1905
var localValidationRunId = currentValidationRunId ;
1894
1906
1895
- // We can update the $$invalidModelValue immediately as we don't have to wait for validators!
1896
- ctrl . $$invalidModelValue = modelValue ;
1897
-
1898
1907
// check parser error
1899
1908
if ( ! processParseErrors ( parseValid ) ) {
1900
1909
return ;
@@ -1971,8 +1980,6 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1971
1980
1972
1981
function validationDone ( ) {
1973
1982
if ( localValidationRunId === currentValidationRunId ) {
1974
- // set the validated model value
1975
- ctrl . $modelValue = ctrl . $valid ? modelValue : undefined ;
1976
1983
1977
1984
doneCallback ( ) ;
1978
1985
}
@@ -2011,31 +2018,31 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
2011
2018
$animate . addClass ( $element , DIRTY_CLASS ) ;
2012
2019
parentForm . $setDirty ( ) ;
2013
2020
}
2021
+ this . $$parseAndValidate ( ) ;
2022
+ } ;
2014
2023
2015
- var parserValid = true , modelValue = viewValue ;
2024
+ this . $$parseAndValidate = function ( ) {
2025
+ var parserValid = true ,
2026
+ viewValue = ctrl . $$lastCommittedViewValue ,
2027
+ modelValue = viewValue ;
2016
2028
for ( var i = 0 ; i < ctrl . $parsers . length ; i ++ ) {
2017
2029
modelValue = ctrl . $parsers [ i ] ( modelValue ) ;
2018
2030
if ( isUndefined ( modelValue ) ) {
2019
2031
parserValid = false ;
2020
2032
break ;
2021
2033
}
2022
2034
}
2023
-
2035
+ var prevModelValue = ctrl . $modelValue ;
2024
2036
ctrl . $$runValidators ( parserValid , modelValue , viewValue , function ( ) {
2025
- ctrl . $$writeModelToScope ( ) ;
2037
+ ctrl . $modelValue = ctrl . $valid ? modelValue : undefined ;
2038
+ if ( ctrl . $modelValue !== prevModelValue ) {
2039
+ ctrl . $$writeModelToScope ( ) ;
2040
+ }
2026
2041
} ) ;
2027
2042
} ;
2028
2043
2029
2044
this . $$writeModelToScope = function ( ) {
2030
- var getterSetter ;
2031
-
2032
- if ( ctrl . $options && ctrl . $options . getterSetter &&
2033
- isFunction ( getterSetter = ngModelGet ( $scope ) ) ) {
2034
-
2035
- getterSetter ( ctrl . $modelValue ) ;
2036
- } else {
2037
- ngModelSet ( $scope , ctrl . $modelValue ) ;
2038
- }
2045
+ ngModelSet ( ctrl . $modelValue ) ;
2039
2046
forEach ( ctrl . $viewChangeListeners , function ( listener ) {
2040
2047
try {
2041
2048
listener ( ) ;
@@ -2123,17 +2130,20 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
2123
2130
} ;
2124
2131
2125
2132
// model -> value
2133
+ // Note: we cannot use a normal scope.$watch as we want to detect the following:
2134
+ // 1. scope value is 'a'
2135
+ // 2. user enters 'b'
2136
+ // 3. ng-change kicks in and reverts scope value to 'a'
2137
+ // -> scope value did not change since the last digest as
2138
+ // ng-change executes in apply phase
2139
+ // 4. view should be changed back to 'a'
2126
2140
$scope . $watch ( function ngModelWatch ( ) {
2127
- var modelValue = ngModelGet ( $scope ) ;
2128
-
2129
- if ( ctrl . $options && ctrl . $options . getterSetter && isFunction ( modelValue ) ) {
2130
- modelValue = modelValue ( ) ;
2131
- }
2141
+ var modelValue = ngModelGet ( ) ;
2132
2142
2133
2143
// if scope model value and ngModel value are out of sync
2134
2144
// TODO(perf): why not move this to the action fn?
2135
- if ( ctrl . $ modelValue !== modelValue &&
2136
- ( isUndefined ( ctrl . $$invalidModelValue ) || ctrl . $$invalidModelValue ! = modelValue ) ) {
2145
+ if ( modelValue !== ctrl . $ modelValue) {
2146
+ ctrl . $modelValue = modelValue ;
2137
2147
2138
2148
var formatters = ctrl . $formatters ,
2139
2149
idx = formatters . length ;
0 commit comments