119

I have an attribute directive restricted as follows:

 restrict: "A"

I need to pass in two attributes; a number and a function/callback, accessing them within the directive using the attrs object.

If the directive was an element directive, restricted with "E" I could to this:

<example-directive example-number="99" example-function="exampleCallback()">

However, for reasons I won't go into I need the directive to be an attribute directive.

How do I pass multiple attributes into an attribute directive?

Undistraction
  • 42,754
  • 56
  • 195
  • 331
  • That depends on the type of scope your directive creates (if any). Choices are: no new scope (default, or explicit with `scope: false`), new scope (with normal prototypal inheritance, i.e., `scope: true`), and isolate scope (i.e., `scope: { ... }`). What type of scope does your directive create? – Mark Rajcok May 14 '13 at 15:11
  • 1
    @MarkRajcok It has an isolate scope. – Undistraction May 14 '13 at 15:32

5 Answers5

206

The directive can access any attribute that is defined on the same element, even if the directive itself is not the element.

Template:

<div example-directive example-number="99" example-function="exampleCallback()"></div>

Directive:

app.directive('exampleDirective ', function () {
    return {
        restrict: 'A',   // 'A' is the default, so you could remove this line
        scope: {
            callback : '&exampleFunction',
        },
        link: function (scope, element, attrs) {
            var num = scope.$eval(attrs.exampleNumber);
            console.log('number=',num);
            scope.callback();  // calls exampleCallback()
        }
    };
});

fiddle

If the value of attribute example-number will be hard-coded, I suggest using $eval once, and storing the value. Variable num will have the correct type (a number).

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • I've edited the example HTML to use snake-case. I know I can't use it as an element. That's the point of the question. – Undistraction May 14 '13 at 17:40
  • @Pedr, yeah, sorry I read too fast about the element usage. I updated the answer, noting that you also need to use snake-case for the attributes too. – Mark Rajcok May 14 '13 at 17:54
  • No problem. Thanks for your answer. I've edited the attribute names to use snake-case. You OK if I remove that from your answer as it was just a silly error by me and distracts from the point of the actual question and answer? – Undistraction May 14 '13 at 17:58
  • I don't get this - how does the directive know to name the exact same thing specified in the directive usage ("exampleCallback()") in its scope? ("callback : '&exampleCallback') Shouldn't the scope be "callback : "&exampleFunction" ? – blaster Sep 07 '13 at 15:03
  • Does this work even if there are multiple directives on the same element? – Fredrik L May 05 '15 at 04:36
  • 1
    @FredrikL, for multiple directives on the same element, please see http://stackoverflow.com/a/28735005/215945 – Mark Rajcok May 05 '15 at 21:21
  • I had this same requirement, except I had to pass in a string array of values. This code gave me the starting point to get it working! Thanks Mark! – James Drinkard Nov 02 '16 at 22:37
  • How can I get `exampleNumber` in controller (updated value, not that which was at the time of creating directive) without defining it in scope parameters? – Somnium Jan 13 '17 at 11:24
20

You do it exactly the same way as you would with an element directive. You will have them in the attrs object, my sample has them two-way binding via the isolate scope but that's not required. If you're using an isolated scope you can access the attributes with scope.$eval(attrs.sample) or simply scope.sample, but they may not be defined at linking depending on your situation.

app.directive('sample', function () {
    return {
        restrict: 'A',
        scope: {
            'sample' : '=',
            'another' : '='
        },
        link: function (scope, element, attrs) {
            console.log(attrs);
            scope.$watch('sample', function (newVal) {
                console.log('sample', newVal);
            });
            scope.$watch('another', function (newVal) {
                console.log('another', newVal);
            });
        }
    };
});

used as:

<input type="text" ng-model="name" placeholder="Enter a name here">
<input type="text" ng-model="something" placeholder="Enter something here">
<div sample="name" another="something"></div>
Undistraction
  • 42,754
  • 56
  • 195
  • 331
Jonathan Rowny
  • 7,588
  • 1
  • 18
  • 26
9

You could pass an object as attribute and read it into the directive like this:

<div my-directive="{id:123,name:'teo',salary:1000,color:red}"></div>

app.directive('myDirective', function () {
    return {            
        link: function (scope, element, attrs) {
           //convert the attributes to object and get its properties
           var attributes = scope.$eval(attrs.myDirective);       
           console.log('id:'+attributes.id);
           console.log('id:'+attributes.name);
        }
    };
});
Bobo
  • 462
  • 8
  • 17
Theo Itzaris
  • 4,321
  • 3
  • 37
  • 68
  • Is it possible to send a boolean value using a object? I tried `{{true}}` but it still returns the string value `true`. – Peter Boomsma Nov 20 '19 at 16:23
4

This worked for me and I think is more HTML5 compliant. You should change your html to use 'data-' prefix

<div data-example-directive data-number="99"></div>

And within the directive read the variable's value:

scope: {
        number : "=",
        ....
    },
jmontenegro
  • 301
  • 4
  • 10
0

If you "require" 'exampleDirective' from another directive + your logic is in 'exampleDirective's' controller (let's say 'exampleCtrl'):

app.directive('exampleDirective', function () {
    return {
        restrict: 'A',
        scope: false,
        bindToController: {
            myCallback: '&exampleFunction'
        },
        controller: 'exampleCtrl',
        controllerAs: 'vm'
    };
});
app.controller('exampleCtrl', function () {
    var vm = this;
    vm.myCallback();
});
Ilker Cat
  • 1,862
  • 23
  • 17