E aí galera, beleza?
Hoje falaremos um pouco sobre as rotas (ngRoute) do AngularJS. Nos posts anteriores falamos sobre controladores e serviços, se você ainda não está familiarizado com o framework recomendo a leitura.
Rotas – Para que servem?
Em aplicações que utilizam o conceito de single page, a navegação de uma página para outra é crucial. Quando a aplicação cresce e se torna mais complexa, precisamos encontrar uma maneira de gerenciar as páginas pelas quais o usuário vai navegar através da aplicação.
Poderíamos fazer toda a aplicação em um único arquivo e gerenciar o modo que a tela se comporta fazendo um gerenciamento de estados (por exemplo, escondendo e exibindo componentes), porém, já sabemos que fazer isso é completamente inviável para manutenção e saúde da aplicação (e da nossa querida saúde também!).
O módulo ngRoute é a solução que precisávamos. Ele nos permite gerenciar os templates a serem inseridos na view de acordo com a navegação do usuário. Ou seja, quando há uma ação de mudança de página, o módulo é capaz de “injetar” o template correspondente (desce mais um pouquinho que te mostro como faz).
Como configurar?
O serviço $routeProvider, que faz parte do módulo ngRoute, é utilizado para realizar a configuração das rotas. Ele facilita a conexão do controlador com o template (view) e a URL que será mapeada com a rota. Com esse recurso, podemos utilizar o histórico do navegador e os favoritos.
Nota: $routeProvider é o provider do serviço $route. Por se tratar de um provider, ele só pode ser injetado dentro da função config. Portanto, não podemos utilizar $routeProvider dentro de um controlador.
Instalação
Para utilizar o angular-route em nossa aplicação, precisamos adicionar a referência do javascript após a referência do próprio AngularJS.
<script src="//code.angularjs.org/1.4.4/angular-route.js"></script>
Depois, devemos adicionar a dependência do módulo ngRoute a nossa app.
angular.module('feira-app',['ngRoute'])
Template
Para utilizar um template, é necessário combinar a diretiva ng-view (linha 10) com a rota. Essa diretiva nos permite especificar exatamente onde no DOM nós queremos renderizar o template de acordo com a rota atual.
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
<!DOCTYPE html>
<html ng-app="feira-app">
<head>
<meta charset="UTF-8">
<title>Blog do Gabriel Feitosa > AngularJS: Rotas (ngRoute)</title>
</head>
<body>
<h1>Animais para Adoção</h1>
<div ng-view style="border: 1px solid"></div>
<div>
<p><b>Vamos ver o que está acontecendo?</b></p>
<pre>Path ($location.path()) = {{$location.path()}}</pre>
<pre>Template ($route.current.templateUrl) = {{$route.current.templateUrl}}</pre>
<pre>Controlador ($route.current.controller) = {{$route.current.controller}}</pre>
<pre>Titulo da Página ($route.current.scope.titulo) = {{$route.current.scope.titulo}}</pre>
<pre>Parâmetros da URL ($routeParams) = {{$routeParams}}</pre>
</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.4/angular.min.js"></script>
<script src="//code.angularjs.org/1.4.4/angular-route.js"></script>
<script src="js/app.js"></script>
<script src="js/config.js"></script>
<script src="js/animal.lista.controller.js"></script>
<script src="js/animal.detalhe.controller.js"></script>
<script src="js/animal.factory.js"></script>
</body>
</html>
Por enquanto não vamos nos preocupar com o restante do código, principalmente os que estão entre as linhas 14 e 18, explicarei na sessão de eventos.
A diretiva ngView segue os seguintes passos:
- Toda vez que o evento $routeChangeSucess é disparado, a view é atualizada;
- Se houver um template associado com a rota atual, um novo escopo é criado;
- A última _view _é removida e, consequentemente, o último escopo é limpo;
- O novo escopo é vinculado ao novo template;
- O controlador é vinculado ao escopo, caso haja um controlador para a rota;
- O evento $viewContentLoaded é disparado.
Configurando as Rotas
A configuração das rotas se dá através dos métodos when e otherwise do serviço $routeProvide. Na nossa aplicação, ele está sendo injetado dentro da função config (linha 6).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(function() {
'use strict';
angular.module('feira-app')
.config(function($routeProvider) {
$routeProvider
.when('/animais', {
templateUrl: 'lista.html',
controller: 'AnimalListaController'
})
.when('/animais/:id', {
templateUrl: 'detalhe.html',
controller: 'AnimalDetalheController'
}).otherwise({
redirectTo: '/animais'
});
});
})();
O método when (linha 7), recebe dois parâmetros (path e route):
O primeiro parâmetro é o path da rota, que é comparado ao $location.path da URL atual. Podemos passar um parâmetro na URL utilizando o :param
, como na nossa rota /animais:id. O resgate desse parâmetro é feito no service $routeparams (linha 18 - index.html).
O segundo parâmetro é o objeto de configuração da rota. É neste momento que definimos qual template e controlador serão injetados. Outras configurações como resolve, redirectTo e reloadOnSearch também são válidas. Os detalhes sobre essas configurações podem ser vistos aqui.
O método otherwise é utilizado para definir uma rota padrão. Assim, quando nenhuma rota for encontrada o AngularJS redirecionará a aplicação para essa rota padrão.
Eventos
O serviço $route dispara eventos em diferentes estágios do fluxo de uma rota. Esses eventos são importantes quando queremos manipular as rotas e são particularmente importantes quando desejamos detectar se um usuário está logado ou não na aplicação.
$routeChangeStart
É disparado antes da mudança da rota. É nesta etapa que todas as dependências necessárias são resolvidas para que a rota mude com sucesso. Uma vez que todas as dependências tenham sido resolvidas o evento $routeChangeSucess é disparado.
Parâmetros:
- angularEvent: objeto de evento;
- next: informação sobre a futura rota;
- current: informação sobre a rota atual;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
(function() {
'use strict';
angular.module('feira-app', ['ngRoute']);
angular.module('feira-app')
.run(function($rootScope, $route, $routeParams, $location) {
$rootScope.$on('$routeChangeStart',function(evt,next,current){
console.log('Nome do Evento:'+evt.name);
console.log('Próxima Rota:'+ angular.toJson(next));
console.log('Rota Atual:'+ angular.toJson(current));
});
$rootScope.$route = $route;
$rootScope.$location = $location;
$rootScope.$routeParams = $routeParams;
});
})();
Aquela explicação que fiquei devendo lá em cima vem agora.
Na função run (linhas 6) estamos setando os services $route, $routeparams e $location no $rootScope. Isso está sendo feito para que possamos utilizar esses serviços na view (linhas 14 a 18 do index.html). Através desses serviços, podemos identificar os parâmetros da URL, qual template e controlador estão sendo injetados na rota atual, entre outras informações.
$routeChangeSuccess
É disparado após a mudança bem sucedida da rota.
Parâmetros:
- angularEvent: o objeto de evento;
- current: informação sobre a rota atual;
- previous: informações da rota anterior, ou undefined se for a primeira rota a ser invocada.
$routeChangeError
Se alguma mudança de rota for rejeitada, esse evento será disparado.
Parâmetros:
- angularEvent: o objeto de evento;
- current: informação sobre a rota atual;
- previous: informações da rota anterior;
- rejection: a _promise _que foi rejeitada.
$routeUpdate
Este evento é disparado se a propriedade reloadOnSearch estiver setada com false e se estivermos reutilizando a mesma instância do controlador.
Parâmetros:
- angularEvent: o objeto de evento;
- current: informação sobre a rota atual/anterior;
Ainda há configurações que não terei espaço para abordar aqui, como o hashbang mode (html5Mode), o hashPrefix e os detalhes do serviço $location.
Existe um outro módulo de rotas chamado AngularUI Router, que utiliza uma abordagem diferente. Particularmente o considero melhor que o ngRoute. Ele é baseado em estados (states) e não em URL. Falaremos mais sobre ele em um futuro post. 😉
Então é isso pessoal, espero que tenham curtido.
Os arquivos do nosso exemplo podem ser visualizados na íntegra no gist ou no repositório de código do blog. Aqui você pode ver a aplicação rodando.
Tem dúvidas, críticas ou sugestões? Deixe um comentário aí que terei o maior prazer em responder.
Abraços e até a próxima!