@@ -1435,6 +1435,12 @@ var VALID_CLASS = 'ng-valid',
1435
1435
* ngModel.$formatters.push(formatter);
1436
1436
* ```
1437
1437
*
1438
+ * @property {Object.<string, function> } $validators A collection of validators that are applied
1439
+ * whenever the model value changes. The key value within the object refers to the name of the
1440
+ * validator while the function refers to the validation operation. The validation operation is
1441
+ * provided with the model value as an argument and must return a true or false value depending
1442
+ * on the response of that validation.
1443
+ *
1438
1444
* @property {Array.<Function> } $viewChangeListeners Array of functions to execute whenever the
1439
1445
* view value has changed. It is called with no arguments, and its return value is ignored.
1440
1446
* This can be used in place of additional $watches against the model value.
@@ -1551,6 +1557,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1551
1557
function ( $scope , $exceptionHandler , $attr , $element , $parse , $animate , $timeout ) {
1552
1558
this . $viewValue = Number . NaN ;
1553
1559
this . $modelValue = Number . NaN ;
1560
+ this . $validators = { } ;
1554
1561
this . $parsers = [ ] ;
1555
1562
this . $formatters = [ ] ;
1556
1563
this . $viewChangeListeners = [ ] ;
@@ -1626,7 +1633,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1626
1633
* Change the validity state, and notifies the form when the control changes validity. (i.e. it
1627
1634
* does not notify form if given validator is already marked as invalid).
1628
1635
*
1629
- * This method should be called by validators - i.e. the parser or formatter functions.
1636
+ * This method can be called within $parsers/$formatters. However, if possible, please use the
1637
+ * `ngModel.$validators` pipeline which is designed to handle validations with true/false values.
1630
1638
*
1631
1639
* @param {string } validationErrorKey Name of the validator. the `validationErrorKey` will assign
1632
1640
* to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
@@ -1743,6 +1751,24 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1743
1751
ctrl . $render ( ) ;
1744
1752
} ;
1745
1753
1754
+ /**
1755
+ * @ngdoc method
1756
+ * @name ngModel.NgModelController#$validate
1757
+ *
1758
+ * @description
1759
+ * Runs each of the registered validations set on the $validators object.
1760
+ */
1761
+ this . $validate = function ( modelValue , viewValue ) {
1762
+ if ( arguments . length === 0 ) {
1763
+ modelValue = ctrl . $modelValue ;
1764
+ viewValue = ctrl . $viewValue ;
1765
+ }
1766
+
1767
+ forEach ( ctrl . $validators , function ( fn , name ) {
1768
+ ctrl . $setValidity ( name , fn ( modelValue , viewValue ) ) ;
1769
+ } ) ;
1770
+ } ;
1771
+
1746
1772
/**
1747
1773
* @ngdoc method
1748
1774
* @name ngModel.NgModelController#$commitViewValue
@@ -1755,12 +1781,12 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1755
1781
* usually handles calling this in response to input events.
1756
1782
*/
1757
1783
this . $commitViewValue = function ( ) {
1758
- var value = ctrl . $viewValue ;
1784
+ var viewValue = ctrl . $viewValue ;
1759
1785
$timeout . cancel ( pendingDebounce ) ;
1760
- if ( ctrl . $$lastCommittedViewValue === value ) {
1786
+ if ( ctrl . $$lastCommittedViewValue === viewValue ) {
1761
1787
return ;
1762
1788
}
1763
- ctrl . $$lastCommittedViewValue = value ;
1789
+ ctrl . $$lastCommittedViewValue = viewValue ;
1764
1790
1765
1791
// change to dirty
1766
1792
if ( ctrl . $pristine ) {
@@ -1771,13 +1797,19 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1771
1797
parentForm . $setDirty ( ) ;
1772
1798
}
1773
1799
1800
+ var modelValue = viewValue ;
1774
1801
forEach ( ctrl . $parsers , function ( fn ) {
1775
- value = fn ( value ) ;
1802
+ modelValue = fn ( modelValue ) ;
1776
1803
} ) ;
1777
1804
1778
- if ( ctrl . $modelValue !== value ) {
1779
- ctrl . $modelValue = value ;
1780
- ngModelSet ( $scope , value ) ;
1805
+ if ( ctrl . $modelValue !== modelValue &&
1806
+ ( isUndefined ( ctrl . $$invalidModelValue ) || ctrl . $$invalidModelValue != modelValue ) ) {
1807
+
1808
+ ctrl . $validate ( modelValue , viewValue ) ;
1809
+ ctrl . $modelValue = ctrl . $valid ? modelValue : undefined ;
1810
+ ctrl . $$invalidModelValue = ctrl . $valid ? undefined : modelValue ;
1811
+
1812
+ ngModelSet ( $scope , ctrl . $modelValue ) ;
1781
1813
forEach ( ctrl . $viewChangeListeners , function ( listener ) {
1782
1814
try {
1783
1815
listener ( ) ;
@@ -1851,26 +1883,31 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
1851
1883
1852
1884
// model -> value
1853
1885
$scope . $watch ( function ngModelWatch ( ) {
1854
- var value = ngModelGet ( $scope ) ;
1886
+ var modelValue = ngModelGet ( $scope ) ;
1855
1887
1856
1888
// if scope model value and ngModel value are out of sync
1857
- if ( ctrl . $modelValue !== value ) {
1889
+ if ( ctrl . $modelValue !== modelValue &&
1890
+ ( isUndefined ( ctrl . $$invalidModelValue ) || ctrl . $$invalidModelValue != modelValue ) ) {
1858
1891
1859
1892
var formatters = ctrl . $formatters ,
1860
1893
idx = formatters . length ;
1861
1894
1862
- ctrl . $modelValue = value ;
1895
+ var viewValue = modelValue ;
1863
1896
while ( idx -- ) {
1864
- value = formatters [ idx ] ( value ) ;
1897
+ viewValue = formatters [ idx ] ( viewValue ) ;
1865
1898
}
1866
1899
1867
- if ( ctrl . $viewValue !== value ) {
1868
- ctrl . $viewValue = ctrl . $$lastCommittedViewValue = value ;
1900
+ ctrl . $validate ( modelValue , viewValue ) ;
1901
+ ctrl . $modelValue = ctrl . $valid ? modelValue : undefined ;
1902
+ ctrl . $$invalidModelValue = ctrl . $valid ? undefined : modelValue ;
1903
+
1904
+ if ( ctrl . $viewValue !== viewValue ) {
1905
+ ctrl . $viewValue = ctrl . $$lastCommittedViewValue = viewValue ;
1869
1906
ctrl . $render ( ) ;
1870
1907
}
1871
1908
}
1872
1909
1873
- return value ;
1910
+ return modelValue ;
1874
1911
} ) ;
1875
1912
} ] ;
1876
1913
0 commit comments