@@ -1577,7 +1577,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1577
1577
1578
1578
var ngModelGet = $parse ( $attr . ngModel ) ,
1579
1579
ngModelSet = ngModelGet . assign ,
1580
- pendingDebounce = null ;
1580
+ pendingDebounce = null ,
1581
+ ctrl = this ;
1581
1582
1582
1583
if ( ! ngModelSet ) {
1583
1584
throw minErr ( 'ngModel' ) ( 'nonassign' , "Expression '{0}' is non-assignable. Element: {1}" ,
@@ -1693,19 +1694,26 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1693
1694
1694
1695
/**
1695
1696
* @ngdoc method
1696
- * @name ngModel.NgModelController#$cancelDebounce
1697
+ * @name ngModel.NgModelController#$cancelUpdate
1697
1698
*
1698
1699
* @description
1699
- * Cancel a pending debounced update.
1700
+ * Cancel an update and reset the input element's value to prevent an update to the `$viewValue`,
1701
+ * which may be caused by a pending debounced event or because the input is waiting for a some
1702
+ * future event.
1700
1703
*
1701
- * This method should be called before directly update a debounced model from the scope in
1702
- * order to prevent unintended future changes of the model value because of a delayed event.
1704
+ * If you have an input that uses `ng-model-options` to set up debounced events or events such
1705
+ * as blur you can have a situation where there is a period when the value of the input element
1706
+ * is out of synch with the ngModel's `$viewValue`. You can run into difficulties if you try to
1707
+ * update the ngModel's `$modelValue` programmatically before these debounced/future events have
1708
+ * completed, because Angular's dirty checking mechanism is not able to tell whether the model
1709
+ * has actually changed or not. This method should be called before directly updating a model
1710
+ * from the scope in case you have an input with `ng-model-options` that do not include immediate
1711
+ * update of the default trigger. This is important in order to make sure that this input field
1712
+ * will be updated with the new value and any pending operation will be canceled.
1703
1713
*/
1704
- this . $cancelDebounce = function ( ) {
1705
- if ( pendingDebounce ) {
1706
- $timeout . cancel ( pendingDebounce ) ;
1707
- pendingDebounce = null ;
1708
- }
1714
+ this . $cancelUpdate = function ( ) {
1715
+ $timeout . cancel ( pendingDebounce ) ;
1716
+ this . $render ( ) ;
1709
1717
} ;
1710
1718
1711
1719
// update the view value
@@ -1764,25 +1772,21 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1764
1772
* @param {string } trigger Event that triggered the update.
1765
1773
*/
1766
1774
this . $setViewValue = function ( value , trigger ) {
1767
- var that = this ;
1768
1775
var debounceDelay = this . $options && ( isObject ( this . $options . debounce )
1769
1776
? ( this . $options . debounce [ trigger ] || this . $options . debounce [ 'default' ] || 0 )
1770
1777
: this . $options . debounce ) || 0 ;
1771
1778
1772
- that . $cancelDebounce ( ) ;
1773
- if ( debounceDelay ) {
1779
+ $timeout . cancel ( pendingDebounce ) ;
1780
+ if ( debounceDelay ) {
1774
1781
pendingDebounce = $timeout ( function ( ) {
1775
- pendingDebounce = null ;
1776
- that . $$realSetViewValue ( value ) ;
1782
+ ctrl . $$realSetViewValue ( value ) ;
1777
1783
} , debounceDelay ) ;
1778
1784
} else {
1779
- that . $$realSetViewValue ( value ) ;
1785
+ this . $$realSetViewValue ( value ) ;
1780
1786
}
1781
1787
} ;
1782
1788
1783
1789
// model -> value
1784
- var ctrl = this ;
1785
-
1786
1790
$scope . $watch ( function ngModelWatch ( ) {
1787
1791
var value = ngModelGet ( $scope ) ;
1788
1792
@@ -2293,4 +2297,4 @@ var ngModelOptionsDirective = function() {
2293
2297
}
2294
2298
} ]
2295
2299
} ;
2296
- } ;
2300
+ } ;
0 commit comments