Cody
Cody

Reputation: 1208

How to update ngModel's $modelValue based on the $viewValue update by user input

Say I have the following directive:

myApp.directive('myDirective', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        scope: {
            ngModel: '='
        },
        link: function(scope, elem, attrs, ngModelCtrl) {
            scope.$watch('ngModel', function() {
                ngModelCtrl.$modelValue = 'foo';
            });
        }
    }
}); 

And the following html:

<input ng-model="name" my-directive></input>

Basically, whenever the user changes the input, my-directive would ideally change the internal model value to "foo" while leaving the view value untouched.

But when I print out $scope.name in the corresponding controller, it doesn't log "foo", it logs whatever the user entered in.

It would seem that ngModelCtrl.$modelValue is not what the controller is accessing -- am I approaching this problem incorrectly?

(Also watching the ngModel in the scope feels really wrong, but I'm not sure of any other way. Any suggestions would be much appreciated!)

Upvotes: 10

Views: 12920

Answers (1)

PSL
PSL

Reputation: 123739

If you are looking for view change, you should never register a watch. ngModelController's $viewChangeListeners are specifically designed for this purpose and to avoid creating any additional watch on the ngModel. You can also remove 2 way binding set up on the ngModel.

I can think of this way.

.directive('myDirective', function($parse) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, elem, attrs, ngModelCtrl) {
          /*Register a viewchange listener*/
          ngModelCtrl.$viewChangeListeners.push(function(){ 
              /*Set model value differently based on the viewvalue entered*/
              $parse(attrs.ngModel).assign(scope, ngModelCtrl.$viewValue.split(',')); 
          });
        }
    }
});

Demo

While thinking about it the other way around (Credits @Cody) it becomes more concise and appropriate while using a $parser.

 ngModelCtrl.$parsers.push(function(val) { return val.split(',') });

Upvotes: 11

Related Questions