How do I pass multiple attributes into an Angular.js attribute directive?
Asked Answered
S

5

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?

Stair answered 14/5, 2013 at 15:8 Comment(2)
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?Kittle
@MarkRajcok It has an isolate scope.Stair
K
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).

Kittle answered 14/5, 2013 at 17:37 Comment(8)
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.Stair
@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.Kittle
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?Stair
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" ?Kearns
Does this work even if there are multiple directives on the same element?Hal
@FredrikL, for multiple directives on the same element, please see https://mcmap.net/q/188814/-angular-1-2-no-longer-allows-multiple-isolated-scope-directives-on-same-elementKittle
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!Unprecedented
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?Houphouetboigny
W
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>
Whereat answered 14/5, 2013 at 17:18 Comment(0)
M
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);
        }
    };
});
Montevideo answered 19/7, 2016 at 12:24 Comment(1)
Is it possible to send a boolean value using a object? I tried {{true}} but it still returns the string value true.Crusted
C
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 : "=",
        ....
    },
Counterclaim answered 21/7, 2015 at 1:3 Comment(0)
G
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();
});
Gladi answered 16/3, 2017 at 17:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.