Como faço para passar vários atributos para uma diretiva de atributo Angular.js?

116

Eu tenho uma diretiva de atributo restrita da seguinte forma:

 restrict: "A"

Eu preciso passar dois atributos; um número e uma função / retorno de chamada, acessando-os dentro da diretiva usando o attrsobjeto.

Se a diretiva fosse uma diretiva de elemento, restrito "E"a isso:

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

No entanto, por motivos que não irei abordar, preciso que a diretiva seja uma diretiva de atributo.

Como faço para passar vários atributos em uma diretiva de atributo?

Undistraction
fonte
Isso depende do tipo de escopo que sua diretiva cria (se houver). As opções são: sem novo escopo (padrão ou explícito com scope: false), novo escopo (com herança prototípica normal, ou seja, scope: true) e escopo isolado (ou seja, scope: { ... }). Que tipo de escopo sua diretiva cria?
Mark Rajcok
1
@MarkRajcok Tem um escopo isolado.
Undistraction

Respostas:

202

A diretiva pode acessar qualquer atributo definido no mesmo elemento, mesmo se a própria diretiva não for o elemento.

Modelo:

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

Diretriz:

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

Se o valor do atributo example-numberfor codificado, sugiro usar $evaluma vez e armazenar o valor. A variável numterá o tipo correto (um número).

Mark Rajcok
fonte
Eu editei o exemplo de HTML para usar snake-case. Eu sei que não posso usar isso como um elemento. Esse é o ponto da questão.
Undistraction
@Pedr, sim, desculpe, li muito rápido sobre o uso do elemento. Atualizei a resposta, observando que você também precisa usar a caixa de cobra para os atributos.
Mark Rajcok
Sem problemas. Obrigado pela sua resposta. Eu editei os nomes dos atributos para usar o caso da cobra. Você está bem se eu remover isso da sua resposta, pois foi apenas um erro bobo da minha parte e me distrai da questão real e da resposta?
Undistraction
Eu não entendo - como a diretiva sabe nomear exatamente a mesma coisa especificada no uso da diretiva ("exampleCallback ()") em seu escopo? ("callback: '& exampleCallback') O escopo não deveria ser" callback: "& exampleFunction"?
blaster
1
@FredrikL, para várias diretivas no mesmo elemento, consulte stackoverflow.com/a/28735005/215945
Mark Rajcok
19

Você faz isso exatamente da mesma maneira que faria com uma diretiva de elemento. Você os terá no objeto attrs, meu exemplo os tem vinculação bidirecional por meio do escopo isolate, mas isso não é obrigatório. Se estiver usando um escopo isolado, você pode acessar os atributos com scope.$eval(attrs.sample)ou simplesmente scope.sample, mas eles podem não ser definidos na vinculação, dependendo da sua situação.

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);
            });
        }
    };
});

usado como:

<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>
Jonathan Rowny
fonte
9

Você poderia passar um objeto como atributo e lê-lo na diretiva como esta:

<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);
        }
    };
});
Theo Itzaris
fonte
É possível enviar um valor booleano usando um objeto? Eu tentei, {{true}}mas ainda retorna o valor da string true.
Peter Boomsma de
4

Isso funcionou para mim e acho que é mais compatível com HTML5. Você deve alterar o seu html para usar o prefixo 'data-'

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

E dentro da diretiva, leia o valor da variável:

scope: {
        number : "=",
        ....
    },
Montenegro
fonte
0

Se você "exigir" 'exampleDirective' de outra diretiva + sua lógica está no controlador 'exampleDirective' (digamos '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
fonte