Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nesting directives within directives

Regarding AngularJS directives I've ran into a situation where I'm calling a directive from within another directive and I have the following questions.

  1. Why can't I referecne scope.bindValue in my link function? Is there a way I can compute a value from scope.bindValue and set it to scope?
  2. Why can the subdirective bind using "@" in scope:{} but not use scope.value = attrs.value in the link function?

All of the below can be seen at http://jsfiddle.net/sdg9/AjDtt/13/

HTML:

<directive bind-value="12" value="7"></directive>

JS:

var myApp = angular.module('myApp', []);
var commonTemplate = '<div>{{name}} bind-value is: {{bindValue}} </div><div>{{name}} value is: {{value}} </div><div>{{name}} add one to bind-value is: {{addOneBindValue}} </div><div>{{name}} add one to value is: {{addOneValue}} </div><br/>';

myApp.directive('directive', function () {
    return {
        scope: {
            bindValue: "@",
        },
        template: commonTemplate + '<br/><sub-directive bind-value="{{value}}" value="{{value}}"></sub-directive>',
        restrict: 'E',
        link: function (scope, element, attrs) {
            scope.name = "Directive";
            scope.value = attrs.value;
            scope.addOneBindValue = parseInt(scope.bindValue) + 1;
            scope.addOneValue = parseInt(scope.value) + 1;
        }
    };
});


myApp.directive('subDirective', function () {
    return {
        scope: {
            bindValue: "@"
        },
        template: commonTemplate,
        restrict: 'E',
        link: function (scope, element, attrs) {   
            scope.name = "SubDirective";
            scope.value = attrs.value;
            scope.addOneBindValue = parseInt(scope.bindValue) + 1;
            scope.addOneValue = parseInt(scope.value) + 1;
        }
    };
});

Output:

Directive bind-value is: 12
Directive value is: 7
Directive add one to bind-value is: null    <--- why?
Directive add one to value is: 8    

SubDirective bind-value is: 7
SubDirective value is:                      <--- why?
SubDirective add one to bind-value is: null
SubDirective add one to value is: null  
like image 593
Steven Avatar asked Mar 15 '13 17:03

Steven


People also ask

What are the three types of directives in Angular?

The three types of directives in Angular are attribute directives, structural directives, and components.

Can a directive have templates?

Components are directives with templates. The only difference between Components and the other two types of directives is the Template. Attribute and Structural Directives don't have Templates.

How many types of directives exist in angular8?

The Angular Directive can be classified into two types: structural and attribute directives. Structural directives alter layout by adding, removing, and replacing elements in DOM.

Can a directive have input?

If we also specify an input property in our directive's class using the same value as the selector property value we can input data into our directive using the attribute on the host element. This instructs Angular that the appBtnGrow class member property is now an input that can receive a value from the host element.


1 Answers

Interpolated attributes (i.e., attributes that use {{}}s) and isolate scope properties defined with '@' are not available when the link function runs. You need to use attrs.$observe() (or scope.$watch( @ property here, ...)) to get the values (asynchronously).

So, scope.bindValue is not available when you are trying to use it.

Similarly, in your subDirective, attribute value has {{}}s, so its value will also not be available when you are trying to use it. You also need to define an '@' directive property for this.

Working fiddle.

The reason for the asynchronous requirement is that the items inside the {{}}s may change, and you normally want your directive to notice (and then do something -- like update the "addOne" values). '@' is normally used with isolate scopes when the attribute value contains {{}}s.

If attribute values are constants, and you're not going to use the values in a template (or templateUrl), then '@' probably shouldn't be used. In the link function, just use attrs.attrName if the value is a string, or scope.$eval(attrs.attrName) if the attribute is a number or boolean (or parseInt(attrs.attrName) if you know it is a number).

like image 114
Mark Rajcok Avatar answered Sep 22 '22 13:09

Mark Rajcok