AngularJS : Pass $scope variable as directive attribute

All we need is an easy explanation of the problem, so here it is.

I’m trying to pass the $scope variable values to a custom directive as attribute, but it’s not working.

Here is the HTML code:

<ul ng-repeat="q in questions">
        <li>
            {{q.question}} 
            <check-list name="{{q.id}}"></check-list>
        </li>
</ul>

The directive is <check-list name={{q.id}}></check-list>, and here is the directive code :

    app.directive('checkList',function(){
    return {
        restrict:'E',
        template: function(elem,attrs){
            console.log(attrs.name);
            return '</br> <input type="radio" /> Yes </br> <input type="radio" /> No'
        },
        link:function(scope,elem,attrs){

        }
    };
})

I’m logging the attribute attrs.name but the value I’m getting is "{{q.id}}" instead of the actual value of q.id

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

I suppose what you want to do is injecting scope object from controller to your directive. So you can define your directive as

app.directive('checkList',function(){
    return {
        restrict:'E',
        scope: {
          name: "="
        }
        template: '{{name}}</br> <input type="radio" /> Yes </br> <input type="radio" /> No',
        link:function(scope,elem,attrs){

        }
    };
}

And in your view, you can reference your directive as

<check-list name="q.id"></check-list>

Method 2

In directives, attributes are just strings.

In a template function, all you can do is use the string value of the attribute. If you want to use the evaluated or interpolated value of the attribute, you have a few options:

1) Use an isolated scope

app.directive('checkList', function() {
    return {
        restrict:'E',
        scope: {
            name: '&'
        }
        template: '</br> <input type="radio" /> Yes </br>{{name()}} <input type="radio" /> No'
        link: function(scope, elem, attrs) {

        }
    };
});

<ul ng-repeat="q in questions">
        <li>
            {{q.question}} 
            <check-list name="q.id"></check-list>
        </li>
</ul>

2) Inject $interpolate or $parse to evaluate the interpolation or expression manually in the link function

app.directive('checkList', function($interpolate) {
    return {
        restrict:'E',
        template: '</br> <input type="radio" /> Yes </br>{{name}} <input type="radio" /> No'
        link:function(scope,elem,attrs){
            scope.name = $interpolate(attrs.name)(scope);
        }
    };
});

<ul ng-repeat="q in questions">
        <li>
            {{q.question}} 
            <check-list name="{{q.id}}"></check-list>
        </li>
</ul>

2a) And finally, $parse

app.directive('checkList',function($parse){
    return {
        restrict:'E',
        template: '</br> <input type="radio" /> Yes </br>{{name}} <input type="radio" /> No'
        link:function(scope,elem,attrs){
            scope.name = $parse(attrs.name)(scope);
        }
    };
});

<ul ng-repeat="q in questions">
        <li>
            {{q.question}} 
            <check-list name="q.id"></check-list>
        </li>
</ul>

Method 3

I think you need to pass “q.id” instead of name={{q.id}} provided $scope.q.id is defined in your corresponding controller.

 <check-list name="q.id"></check-list>

Method 4

Or pass the entire scope to your directive:

app.directive('checkList',function(){
    return {
        restrict:'E',
        scope: true, //scope
        template: function(elem,attrs){
            console.log(attrs.name);
            return '</br> <input type="radio" /> Yes </br> <input type="radio" /> No'
        },
        link:function(scope,elem,attrs){
           var question = scope.q; //get your question here
        }
    };
})

I recommend you pass only reference type as argument to your directive. Do not pass primitive types (q.id may be an integer). Pass question instead. It’s all about how angularjs utilizes prototypical inheritance.

Scope is a complex topic in angularjs. See this: https://github.com/angular/angular.js/wiki/Understanding-Scopes

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply