@@ -709,7 +709,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
709
709
} ;
710
710
711
711
this . $$writeModelToScope = function ( ) {
712
- ngModelSet ( $scope , ctrl . $modelValue ) ;
712
+ ngModelSet ( $scope , modelValueGetter ( ctrl . $modelValue ) ) ;
713
713
forEach ( ctrl . $viewChangeListeners , function ( listener ) {
714
714
try {
715
715
listener ( ) ;
@@ -806,43 +806,80 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
806
806
}
807
807
} ;
808
808
809
- // model -> value
810
- // Note: we cannot use a normal scope.$watch as we want to detect the following:
811
- // 1. scope value is 'a'
812
- // 2. user enters 'b'
813
- // 3. ng-change kicks in and reverts scope value to 'a'
814
- // -> scope value did not change since the last digest as
815
- // ng-change executes in apply phase
816
- // 4. view should be changed back to 'a'
817
- $scope . $watch ( function ngModelWatch ( ) {
809
+ this . $$setupModelWatch = function ( ) {
810
+ // model -> value
811
+ // Note: we cannot use a normal scope.$watch as we want to detect the following:
812
+ // 1. scope value is 'a'
813
+ // 2. user enters 'b'
814
+ // 3. ng-change kicks in and reverts scope value to 'a'
815
+ // -> scope value did not change since the last digest as
816
+ // ng-change executes in apply phase
817
+ // 4. view should be changed back to 'a'
818
+
819
+ // options.deepWatch
820
+ // options.collection
821
+
822
+ setModelValueHelpers ( ) ;
823
+ $scope . $watch ( ngModelWatch ) ;
824
+ } ;
825
+
826
+ var modelValueGetter = function modelValueGetter ( modelValue ) {
827
+ return modelValue ;
828
+ } ;
829
+
830
+ var modelValueChanged = function modelValueChanged ( newModelValue , currentModelValue ) {
831
+ return newModelValue !== currentModelValue ;
832
+ } ;
833
+
834
+ /**
835
+ * If ngModelOptions deepWatch is true, then the model must be copied after every view / scope
836
+ * change, so we can correctly detect changes to it with .equals(). Otherwise, the ctrl.$modelValue
837
+ * and the scope value are the same, and we cannot detect differences to them properly
838
+ */
839
+ function setModelValueHelpers ( ) {
840
+ if ( ctrl . $options && ctrl . $options . deepWatch ) {
841
+ modelValueGetter = function modelValueGetter ( modelValue ) {
842
+ return copy ( modelValue ) ;
843
+ } ;
844
+
845
+ modelValueChanged = function modelValueChanged ( newModelValue , currentModelValue ) {
846
+ return ! equals ( newModelValue , currentModelValue ) ;
847
+ } ;
848
+ }
849
+ }
850
+
851
+ function ngModelWatch ( ) {
818
852
var modelValue = ngModelGet ( $scope ) ;
819
853
820
854
// if scope model value and ngModel value are out of sync
821
- // TODO(perf): why not move this to the action fn?
822
- if ( modelValue !== ctrl . $modelValue &&
855
+ if ( modelValueChanged ( modelValue , ctrl . $modelValue ) &&
823
856
// checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
824
857
( ctrl . $modelValue === ctrl . $modelValue || modelValue === modelValue )
825
858
) {
826
- ctrl . $modelValue = ctrl . $$rawModelValue = modelValue ;
827
- parserValid = undefined ;
859
+ modelToViewAction ( modelValue ) ;
860
+ }
861
+ return modelValue ;
862
+ }
828
863
829
- var formatters = ctrl . $formatters ,
830
- idx = formatters . length ;
864
+ function modelToViewAction ( modelValue ) {
865
+ ctrl . $modelValue = ctrl . $$rawModelValue = modelValueGetter ( modelValue ) ;
866
+ parserValid = undefined ;
831
867
832
- var viewValue = modelValue ;
833
- while ( idx -- ) {
834
- viewValue = formatters [ idx ] ( viewValue ) ;
835
- }
836
- if ( ctrl . $viewValue !== viewValue ) {
837
- ctrl . $viewValue = ctrl . $$lastCommittedViewValue = viewValue ;
838
- ctrl . $render ( ) ;
868
+ var formatters = ctrl . $formatters ,
869
+ idx = formatters . length ;
839
870
840
- ctrl . $$runValidators ( modelValue , viewValue , noop ) ;
841
- }
871
+ var viewValue = modelValue ;
872
+ while ( idx -- ) {
873
+ viewValue = formatters [ idx ] ( viewValue ) ;
842
874
}
875
+ if ( ctrl . $viewValue !== viewValue ) {
876
+ ctrl . $viewValue = ctrl . $$lastCommittedViewValue = viewValue ;
877
+ ctrl . $render ( ) ;
878
+
879
+ ctrl . $$runValidators ( modelValue , viewValue , noop ) ;
880
+ }
881
+ }
843
882
844
- return modelValue ;
845
- } ) ;
846
883
} ] ;
847
884
848
885
@@ -1032,6 +1069,7 @@ var ngModelDirective = ['$rootScope', function($rootScope) {
1032
1069
formCtrl = ctrls [ 1 ] || modelCtrl . $$parentForm ;
1033
1070
1034
1071
modelCtrl . $$setOptions ( ctrls [ 2 ] && ctrls [ 2 ] . $options ) ;
1072
+ modelCtrl . $$setupModelWatch ( ) ;
1035
1073
1036
1074
// notify others, especially parent forms
1037
1075
formCtrl . $addControl ( modelCtrl ) ;
0 commit comments