3

I want to check the changing of a value in a custom directive.
To do this, I use $parsers unshift-function to add my own function

But, my own function is not called!

This is my view:

<div ng-controller="MyCtrl">
    <form novalidate name="myForm">
        Number: <even-number name="awesomeField" ng-model="val"></even-number>
    </form>
</div>

This is my javasript code:

var myApp = angular.module('myApp',[]);

function MyCtrl($scope) {
    $scope.val = "42";
    $scope.$watch('val', function() {
        console.log("Controller: "+$scope.val);
    });
}

myApp.directive('evenNumber', function(){
    var tmplt = ''+
    '<div class="input-group">'+
        '<input class="form-control" name="inputDate" type="text" data-ng-model="ngModel"/>'+
        '<span class="input-group-btn">'+
            '<button class="btn btn-default">Default</button>'+
        '</span>'+
    '</div>';
    return {
        restrict: 'E',
        require:'ngModel',
        replace: true,
        template: tmplt,
        scope: {
            ngModel: "="
        },
        link: function(scope, elem, attrs, ctrl){
            ctrl.$parsers.unshift(checkValue);

            function checkValue(viewValue){
                console.log("halllllo");
                return viewValue;
            }
        } // end link
    }; // end return
});

What's the problem here?

Here it is as a jsFiddle

2
  • Is there anything that you don't understand in my answer so I can improve it? Commented Dec 23, 2014 at 9:40
  • thank you very much for your detailed answer. Right now, I didn't have the time to improve it. I will answer after all that holiday-stuff. Ok? What else? Ah yeah: MMMMmmmerry Xmas :) Commented Dec 24, 2014 at 11:15

1 Answer 1

1

Write your directive as an attribute directive to be used on the <input /> element what ngModel knows how to handle already. Wrapping the input like that will not work with ngModel. You will need two directives to achieve what you need. One that bundles the input and the button (event-number) and a second one that attaches to the input itself to perform any conversions using $parsers model --> view & $formatters view --> model.

Update Here is a working example:

var myApp = angular.module('myApp',[]);

function MyCtrl($scope) {
    $scope.val = "42";
    $scope.$watch('val', function() {
        console.log("Controller: "+$scope.val);
    });
}

myApp
.directive('evenNumberConverter', function(){
    return {
        restrict: 'A',
        require:'ngModel',
        link: function(scope, elem, attrs, ctrl){
            ctrl.$parsers.unshift(checkValue);
       
            function checkValue(viewValue){
                console.log("halllllo");
                return viewValue;
            }
        } // end link
    }; // end return
})
.directive('evenNumber', function(){
    var tmplt = ''+
    '<div class="input-group">'+
        '<input class="form-control" name="inputDate" type="text" even-number-converter data-ng-model="value"/>'+
        '<span class="input-group-btn">'+
            '<button class="btn btn-default" data-ng-click="setDefault()">Default</button>'+
        '</span>'+
    '</div>';
    return {
        restrict: 'E',
        replace: true,
        template: tmplt,
        scope: {
            value: "="
        },
        link: function(scope, elem, attrs, ctrl){
            scope.setDefault = function() {
              scope.value = 0;
            };
        } // end link
    }; // end return
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
    <form novalidate name="myForm">
        Number ({{val}}): <even-number name="awesomeField" value="val"></even-number>
    </form>
</div>

Notes: the thing is that your directive does not use any of the ngModelController methods for sending the value to the view compontent and reading it back to the model. Its a simple "wrapper" directive and as such the ngModel on the scope could as well be named any other way.

This is because the ngModel directive does not know anything about your "even-number" element. In order to do so you would have to override and use the $render() method to present the value and when reading from UI a new value use the $setViewValue(). Only then the $parsers and $formatters are triggered, otherwise an ngModel scope variable behaves as any other.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.