Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!)

like image 732
Cody Avatar asked Oct 03 '14 01:10

Cody


1 Answers

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(',') });
like image 140
PSL Avatar answered Nov 07 '22 23:11

PSL