Olá pessoal, beleza?
No post anterior, Introdução ao AngularJS, fizemos uma explanação sobre algumas características importantes do AngularJS. Hoje vamos falar sobre os controladores e as boas práticas que podem ser adotadas em sua utilização.
Entendendo os Controladores
Os Controladores (Controllers), como o próprio nome diz, são responsáveis pelo controle da aplicação. É neles que gerenciamos o fluxo de dados apresentados na view. Quando um controlador é anexado ao DOM, via ng-controller, um novo objeto do controlador será instanciado, de acordo com a especificação do construtor. Na sequência, um novo escopo ($scope) filho será criado e disponibilizado como um parâmetro injetável no construtor do controlador.
[Boa Prática]
- O controlador deve ser utilizado apenas para a lógica de negócio da aplicação. É nele que devemos setar o estado inicial do $scope e/ou adicionar comportamento.
- Não é recomendado usá-lo para:
- Manipular o DOM: para a manipulação do DOM é aconselhável utilizar diretivas, com o intúito de encapsular esse comportamento. Ademais, com essa prática o código fica mais manutenível e testável.
- Formatar Inputs: para isso use os controladores de formulários.
- Filtrar Dados: o AngularJS dispõe de filtros padrão, além da opção de escrever filtros customizados.
- Compartilhar código: para compartilhar estados ou dados com outros controladores devemos utilizar as factories/services.
Vamos pegar o exemplo do post Introdução ao AngularJS e adicionar o controlador, aqui você pode vê-lo rodando:
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
<!DOCTYPE html>
<!--Declaração do módulo da aplicação-->
<html ng-app="app">
<head>
<meta charset="utf-8">
<title>Exemplo 1 - Blog do Gabriel Feitosa</title>
</head>
<body>
<h1>Entendendo os Controladores</h1>
<!--Declaração do nosso MeuController-->
<div ng-controller="MeuController">
<input type="text" ng-model="nome" placeholder="Diz teu nome aí" />
<h1>Eita , o controlador setou o estado inicial do $scope.nome!</h1>
</div>
<footer>
<hr>
<a href="http://www.gabrielfeitosa.com"> Blog do Gabriel Feitosa</a>
</footer>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script>
//Declarando o módulo da aplicação
var app = angular.module('app', []);
//Declarando o construtor do MeuController
app.controller('MeuController', ['$scope', function($scope) {
$scope.nome = 'Gabriel';
}]);
</script>
</body>
</html>
Neste exemplo, criamos o controlador (MeuController) no módulo app, utilizando o método controller(). Esse método o mantém fora do escopo global. O objeto $scope é inserido dentro do MeuController através do mecanismo de injeção de dependência. Depois utilizamos a diretiva ng-controller, na div, para anexar o nosso controlador ao DOM.
Adicionando comportamento ao $scope
Quando queremos executar alguma ação na view, precisamos adicionar comportamento ao escopo. Antes disso, no entanto, é necessário anexar os métodos ao $scope. Assim, eles ficarão disponíveis para a camada de visão.
O código abaixo pode ser visto rodando aqui.
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
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="utf-8" />
<title>Exemplo 2 - Blog do Gabriel Feitosa</title>
</head>
<body>
<h1>Entendendo os Controladores</h1>
<div ng-controller="MeuController">
<form>
<input type="text" ng-model="item" placeholder="Informe um item" />
<button ng-click="addItem()">Adicionar</button>
</form>
<br/>
<h1> Itens</h1>
<ul>
<li ng-repeat="i in itens"></li>
</ul>
</div>
<footer>
<hr/>
<a href="http://www.gabrielfeitosa.com"> Blog do Gabriel Feitosa</a>
</footer>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script>
var app = angular.module('app', []);
app.controller('MeuController', ['$scope', function($scope) {
$scope.item = '';
$scope.itens = [];
$scope.addItem = function() {
$scope.itens.push($scope.item);
$scope.item = '';
}
}]);
</script>
</body>
</html>
Para adicionar um item a lista de ítens, foi anexado ao $scope o método addItem ($scope.addItem). Já para utilizar o método addItem, utilizamos a diretiva ng-click. Sempre que houver o evento de click no botão o método será chamado.
Para exibir os itens adicionados utilizamos a diretiva ng-repeat. Quando um item for adicionado um novo elemento <li> será criado.
Nota: Para evitar o erro Error: ngRepeat:dupes na diretiva ng-repeat quando adicionamos ítens duplicados, é necessário usar o
track by
. O uso é indispensável porque o AngularJS utiliza uma chave única para ligar o nó do DOM ao elemento que está iterando. Mais detalhes sobre o assunto aqui.
Herança de $scope
Quando adicionamos os controllers em hierarquias, um dentro do outro, temos uma herança de escopos. Isso acontece porque a diretiva ng-controller cria um novo $scope filho, então o $scope que cada controlador recebe terá acesso aos métodos e atributos do controlador acima na hierarquia.
O código abaixo pode ser visto rodando aqui
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
<!DOCTYPE html>
<!--Declaração do módulo da aplicação-->
<html ng-app="app">
<head>
<meta charset="utf-8"/>
<title>Exemplo 3 - Blog do Gabriel Feitosa</title>
<style type="text/css">
div.heranca div {
padding: 5px;
border: solid 2px #000;
}
</style>
</head>
<body>
<h1>Entendendo os Controladores - Herança de $scope</h1>
<!--Declaração do nosso MeuController-->
<div class="heranca">
<div ng-controller="PaiController">
<p>Eu sou !</p>
<div ng-controller="FilhoController">
<p>Eu sou </p>
<div ng-controller="NetoController">
<p>Eu sou </p>
</div>
</div>
</div>
</div>
<footer>
<hr/>
<a href="http://www.gabrielfeitosa.com"> Blog do Gabriel Feitosa</a>
</footer>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.3/angular.min.js"></script>
<script>
var app = angular.module('app',[]);
app.controller('PaiController',['$scope',function($scope){
$scope.nome = 'Gabriel';
$scope.sobrenome='Feitosa';
}]);
app.controller('FilhoController',['$scope',function($scope){
$scope.nome = 'Lampião';
}]);
app.controller('NetoController',['$scope',function($scope){
$scope.sobrenome='Junior';
}]);
</script>
</body>
</html>
Como resultado desse aninhamento de controladores, são criados quatro objetos $scope (o root scope e um $scope para cada controlador). Para acessar uma propriedade do escopo pai, nós usamos o $parent.
Ainda há propriedades dos controladores que podem ser exploradas como, por exemplo, o uso do controller as ao invés do $scope. Vocês podem ver nesse plunker um exemplo utilizando o controller as e outras boas práticas, como o conceito de responsabilidade única (single responsability) para os arquivos javascript.
Por hoje é isso pessoal, espero que tenham gostado.
Abraços e até a próxima!