iJade
iJade

Reputation: 23801

AngularJS : Pass $scope variable as directive attribute

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

Upvotes: 15

Views: 48759

Answers (4)

Joe Enzminger
Joe Enzminger

Reputation: 11190

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>

Upvotes: 10

roland
roland

Reputation: 7775

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

Upvotes: 2

Rebornix
Rebornix

Reputation: 5270

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>

Upvotes: 21

MaheshMG
MaheshMG

Reputation: 41

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>

Upvotes: 2

Related Questions