E se a aplicação começar a crescer?
Até agora, construímos aplicações AngularJS que mostravam dados na tela, através da camada view. Mas e se a aplicação for crescendo e precisar exibir mais informações na tela? Anexar mais pedaços de código a uma view pode transformá-la numa bagunça rapidamente.
A melhor solução é usar múltiplos templates (views) que mostram diferentes partes dos dados, tendo como base a URL que o usuário está visitando. Podemos fazer isso com as chamadas rotas de aplicação do AngularJS. Vamos precisar criar vários arquivos e pastas para este projeto (Obs: os códigos de cada arquivo estarão no final deste capítulo):
- O arquivo
app.jsemjs/; - Os arquivos
HomeController.jsePhotoControlleremjs/controllers/; photos.jsemjs/services/;- A pasta
js/views, que guardará os arquivosphoto.htmlehome.html;
Vamos ver um exemplo de como isso pode ser feito. Na camada index.html, vamos adicionar as tags <div ng-view></div> num lugar específico (sugerido pelo tutorial CodeCademy). Dentro do arquivo app.js, escrevemos isso:
var app = angular.module('GalleryApp', ['ngRoute']);
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'HomeController',
templateUrl: 'views/home.html'
})
.otherwise({
redirectTo: '/'
});
});
No método app.config() usamos o $routeProvider, que define as rotas de aplicação. Depois, usamos .When() para direcionar a URL para um controlador (no nosso caso, HomeController) e um template home.html. O HomeController usa o serviço js/services/photos.js, que pega um array externo e guarda na $scope.photos, dentro de HomeController. O template home.html usa a diretiva ng-repeat para exibir cada item daquele array de fotos que o serviço acessa.
Caso o usuário acidentalmente visite outra URL, .Otherwise() o redireciona para a URL /. Incluindo home.html dentro de <div ng-view> </ div>, em index.html, o usuário será redirecionado para lá.
Agora é hora de adicionar mais templates ao projeto. O que acontece quando o usuário clicar nas fotos? Até agora, nada. Mas vamos mudar isso, adicionando mais uma condição .when() à nossa app.js, assim:
var app = angular.module('GalleryApp', ['ngRoute']);
app.config(function ($routeProvider) {
$routeProvider
.when('/', {
controller: 'HomeController',
templateUrl: 'views/home.html'
})
.when('/photos/:id', {
controller: 'PhotoController',
templateUrl: 'views/photo.html'
})
.otherwise({
redirectTo: '/'
});
});
Agora, se o usuário clicar em alguma das fotos do array que recebemos do serviço, um novo template se mostrará. Mas como fizemos isso?
Nós simplesmente mapeamos uma URL à PhotoController e a photo.html, para que pudéssemos acessar outras templates do projeto. No controlador PhotoController, usamos o $routeParams.id para recuperar os dados da URL. Note que incluímos $routeParams e o serviço Photos dentro de PhotoController, para que pudéssemos usá-los dentro deste controlador. O PhotoController tem o código abaixo:
app.controller('PhotoController', ['$scope', 'photos', '$routeParams', function($scope, photos, $routeParams) {
photos.success(function(data) {
$scope.detail = data[$routeParams.id];
});
}]);
Para acessar cada foto, primeiro usamos o serviço que recebe os dados de um servidor externo (as fotos), e as acessamos pelo indice de cada uma das fotos através de $routeParams.id.
Assim como no exemplo anterior, qualquer propriedade anexada a $scope se torna disponível para acesso. Isto significa que, em photo.html, podemos usar expressões para exibir detalhes ($scope.detail, que está em PhotoController) de cada foto. Em photo.html, encontramos esse código:
<div class="photo">
<div class="container">
<img ng-src="{{ detail.url }}">
<h2 class="photo-title"> </h2>
<p class="photo-author"> </p>
<p class="photo-views"> </p>
<p class="photo-upvotes"> </p>
<p class="photo-pubdate"> </p>
</div>
</div>
Note que ainda não estamos exibindo informações sobre as fotos quando clicamos nelas. É porque não usamos as expressões para mostrá-las ainda. Dentro do template photo.html, temos que adicionar expressões que mostram os detalhes das fotos, assim:
<div class="photo">
<div class="container">
<img ng-src="{{ detail.url }}">
<h2 class="photo-title"> </h2>
<p class="photo-author"> </p>
<p class="photo-views"> {{photo.views|number}}</p>
<p class="photo-upvotes"> {{photo.upvotes|number}}</p>
<p class="photo-pubdate"> {{photo.pubdate|date}}</p>
</div>
</div>
Como prometido, abaixo estão os códigos completos de cada arquivo que usamos no tutorial. Porém, um aviso: é provável que alguma parte faça com que o projeto não funcione, pois os arquivos fonte de alguns deles estão em servidores externos.
Código da index.html:
<!doctype html>
<html>
<head>
<link href="https://s3.amazonaws.com/codecademy-content/projects/bootstrap.min.css" rel="stylesheet" />
<link href='https://fonts.googleapis.com/css?family=Roboto:400,500,300' rel='stylesheet' type='text/css'>
<link href="css/main.css" rel="stylesheet" />
<!-- Include the core AngularJS library -->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
<!-- Include the AngularJS routing library -->
<script src="https://code.angularjs.org/1.2.28/angular-route.min.js"></script>
</head>
<body ng-app="GalleryApp">
<div class="header">
<div ng-view></div>
<div class="container">
<a href="/#/">
<img src="img/logo.svg" width="80" height="80"> フ ォ ト フ ォ ト
</a>
</div>
</div>
<!-- Modules -->
<script src="js/app.js"></script>
<!-- Controllers -->
<script src="js/controllers/HomeController.js"></script>
<script src="js/controllers/PhotoController.js"></script>
<!-- Services -->
<script src="js/services/photos.js"></script>
</body>
</html>
Código de home.html
<div class="main">
<div class="container">
<h2>Recent Photos</h2>
<div class="row">
<div class="item col-md-4" ng-repeat="photo in photos">
<a href="#/photos/{{$index}}">
<img class="img-responsive" ng-src="{{ photo.url }}">
<p class="author">by {{ photo.author }}</p>
</a>
</div>
</div>
</div>
</div>
Código de photo.html
<div class="photo">
<div class="container">
<img ng-src="{{ detail.url }}">
<h2 class="photo-title"> </h2>
<p class="photo-author"> </p>
<p class="photo-views"> {{ detail.views | number }} </p>
<p class="photo-upvotes"> {{ detail.upvotes | number }} </p>
<p class="photo-pubdate"> {{ detail.pubdate | date }}</p>
</div>
</div>
Código de HomeController.js
app.controller('HomeController', ['$scope', 'photos', function($scope, photos) {
photos.success(function(data) {
$scope.photos = data;
});
}]);
Código de PhotoController.js
app.controller('PhotoController', ['$scope', 'photos', '$routeParams', function($scope, photos, $routeParams) {
photos.success(function(data) {
$scope.detail = data[$routeParams.id];
});
}]);