Fala galera!
Semana passada, recebi um e-mail perguntando se eu tinha algum exemplo, com AngularJS, para controlar as permissões de acesso do usuário aos botões da aplicação. Pensei: porquê não juntar a fome com a vontade de comer e blogar a respeito? Então vamos nessa!
Diretiva
Antes de colocar a mão na massa, é importante saber que o melhor lugar para se manipular o DOM é dentro de uma directive. Isso se deve ao comportamento do Angular HTML Compiler. Pode parecer meio estranho falar sobre compilar, mas é graças ao HTML Compiler que podemos anexar comportamento a qualquer elemento HTML ou adicionar atributos.
Uma dica importante refere-se a normalização dos nomes das diretivas. O AngularJS geralmente utiliza camelCase para normalizá-las (exemplo: ngRepeat e ngModel). Porém, temos que lembrar que o HTML não é case sensitive. Por esse motivo, usamos letras minúsculas e mais um traço separando as palavras (ng-repeat e ng-model) para utilizar as diretivas no DOM .
O nome da nossa diretiva de acesso será “permissaoAcesso“. Ela terá a restrição de ser utilizada unicamente como atributo em um elemento do DOM. E é aqui que pode surgir a dúvida: “mas Gabriel, tem como restringir como a diretiva vai ser utilizada?”
A resposta é sim. As diretivas possuem a opção de restringir como serão usadas. Essa opção é a restrict e ela obedece os seguintes parâmetros:
- A: só pode ser utilizada como atributo.
- E: só pode ser utilizada como elemento.
- C: só pode ser utilizada como classe (class) css.
- M: só pode ser utilizada como comentário.
Mas e se eu quiser usar como elemento e atributo, como faço? Aí é só mesclar com as letras que você desejar, por exemplo ‘AECM’, que libera o uso da diretiva em todas as opções mencionadas acima.
Por default, a opção restrict será ‘AE’. Ou seja, poderá ser utilizada como elemento e atributo.
Construindo a diretiva permissaoAcesso
Para iniciar, vamos criar uma página HTML que exibirá os elementos (botão e link). A regra é que se o usuário não possuir a permissão de acesso o elemento deverá ser desabilitado, caso contrário ele será exibido normalmente.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<!DOCTYPE html>
<html ng-app="acesso">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
<title>Blog do Gabriel Feitosa</title>
<link rel="stylesheet" href="font-awesome/css/font-awesome.min.css">
<style>
.block {
margin-left: 5px;
color: red;
}
a[disabled] {
pointer-events: none;
}
td {
padding: 5px
}
</style>
</head>
<body>
<h1>AngularJS: Diretiva de acesso</h1>
<table>
<th>
<tr>
<td></td>
<td>Botão</td>
<td>Link</td>
</tr>
</th>
<tr>
<td>Com Restrição</td>
<td>
<button permissao-acesso="block" onclick="alert('Ops, deu errado!')">Botão</button>
</td>
<td>
<a href="" permissao-acesso="block" onclick="alert('Ops, deu errado!')">Link</a>
</td>
</tr>
<tr>
<td>Sem Restrição</td>
<td>
<button permissao-acesso="no-block" onclick="alert('Aeee \\o/, botão liberado!')">Botão</button>
</td>
<td>
<a href="" permissao-acesso="no-block" onclick="alert('Aeee \\o/, link liberado!')">Link</a>
</td>
</tr>
</table>
<footer>
<hr/>
<a href="https://gabrielfeitosa.com"> Blog do Gabriel Feitosa</a>
</footer>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="js/app.js"></script>
</body>
</html>
Como pode ser visto no código acima, os elementos “button” e “a” possuem a nossa diretiva “permissao-acesso”. A diretiva está recebendo um valor (block e no-block) que será utilizado na nossa lógica para bloquear ou não o elemento.
O evento de click dos elementos está configurado com um alert. Assim, uma mensagem será exibida caso consigamos clicar no elemento.
Para incrementar a diretiva, utilizei a lib Font Awesome, para adicionar um ícone quando o elemento estiver bloqueado (só frescura mesmo! ;))
Agora vamos ver a implementação da nossa diretiva permissaoAcesso:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(function(){
angular.module('acesso',[])
.directive('permissaoAcesso', function(){
return {
restrict: 'A',
link: function ($scope, element, attrs) {
if (attrs.permissaoAcesso === 'block') {
element.attr('disabled', 'disabled');
element.append('<span class="block fa fa-lock"></span>');
}
}
};
});
})();
Perceba que o primeiro parâmetro da diretiva é o restrict com valor “A”. Como dito anteriormente, essa diretiva só poderá ser utilizada como um atributo.
Em seguida, temos uma novidade que é a opção link. É aqui que normalmente manipulamos o DOM e colocamos a nossa lógica de negócio. A função do link é executada após o template ser clonado e recebe cinco parâmetros:
- scope: o objeto $scope do AngularJS.
- element: é o elemento que está sendo processado. Esse elemento está dentro de um wrapper do jqLite.
- attrs: é um hash dos atributos e seus respectivos valores que estão presentes no elemento.
- controller: é uma instância do controlador.
- transcludeFn: é um link para a função de transclude.
A lógica de negócio da nossa diretiva só utiliza os parâmetros attrs e element.
O attrs é utilizado para ter acesso ao valor do atributo permissaoAcesso e verificar se o conteúdo dele é block. Caso a condição seja verdadeira, iremos manipular o elemento através do parâmetro element. A ideia é bem simples: adicionamos ao elemento um atributo disabled para bloqueá-lo. Na sequência, incorporamos um elemento span com o ícone do Font Awesome, o que será feito através do element.append.
A Figura 1 exibe o resultado do uso da diretiva. O exemplo do código está rodando aqui e os fontes estão no github.
Há muito mais coisas para comentar sobre diretivas, como o isolamento do escopo, $compile, transclude. Vale a pena dar uma olhada na documentação oficial, que por sinal é muito rica.
Usando a imaginação dá para incrementar a diretiva para outros elementos HTML e adicionar ou remover um comportamento de acordo com o tipo do elemento. Lembre que você tem em mãos um wrapper do elemento em jqLite, que é um subconjunto do jQuery.
Bom, por hora é isso pessoal. Espero que tenham curtido a postagem de hoje.
Abraços e até a próxima!