2

I have a really weird Problem about formatters in nested directives.

I want a modelType directive for formatting.
If I don't check the "modelType", it works.
All View-Values are changed to "Formatted: ...".

But if i implement the if (attrs.modelType == "testType") { ... } it wont work, but i don't know why.

myApp.directive('modelType', function(){
return {
restrict: 'A',
require: 'ngModel',
    link: function(scope, element, attrs, ngModel) {
      if(attrs.modelType == "testType") {
      ngModel.$formatters.push(function(value){
        //formats the value for display when ng-model is changed
        return 'Formatted: ' + value; 
      });
      ngModel.$parsers.push(function(value){
        //formats the value for ng-model when input value is changed
        return value.slice(11); 
      });
    }
  }
};

Does anyone know this Problem?

http://jsfiddle.net/nkop2uq0/2/

2
  • Please include your relevant code with the question. Commented Feb 22, 2016 at 19:14
  • okay, i have edited my post Commented Feb 23, 2016 at 8:35

1 Answer 1

1

First, using the attribute model-type both in the outer and inner directive led to the inner's link function getting executed twice (once for the controller-owned HTML, once for the template HTML), overwriting your formatting. So you need (or at least I think you should) disentagle the attribute for the two directives by using a different attribute for the inner directive:

 template: '<div><input type="text" ng-model="ngModel" my-type="modelType" /></div>'

and consequently rename the inner directive to

 myApp.directive('myType', function(){ 

Next, since the inner directive now does no longer get called by the compile step for the outer one, you need to compile the template for the inner directive in your post-link function

This can be done like this:

 link: function (scope, element){
    $compile(element.innerHtml)(scope)
 }

This leads to attrs being always the same, so you can't use it to test for your testType:

$$element: U[1]
$$observers: Object
$attr: Object
myType: "modelType"  <-- see here
ngModel: "ngModel"
type: "text"

Therefore you need to to look for the actual value inside scope:

if(scope.modelType == "testType") {

Lastly (and frankly I would be happy if someone could explain this to me, I don't understand it), I had to define the modelType scope property in the outer directive as one-way bound via

modelType: '@modelType'

I put this together in an updated fiddle here: http://jsfiddle.net/nkop2uq0/8/

NB: I am far from understanding the intricacies of Angular's directives. As much as I like the framework, the number of ways things can be achieved is mind-boggling. So you should try to improve my answer, it is most likely not best practice. And drop me a line if you find bad ideas in there...

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

3 Comments

Thank u very much :)
My pleasure. It was an interesting challenge for sure.
i've recognized that it works without the "$compile". And i have another Problem in the same context. Now i use $filter('date')(value, 'short'); in the formatter function. But the i18n is not changing the Date format between DE and EN. The ng-model is two way binding, so why it does not change? Thank you :)

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.