Criando um site em 15 minutos com AngularJS
Introdução
Qual é a vantagem essencial do Angular? Se você é um novato na construção de seu próprio site, ou um profissional procurando uma vantagem sobre como aprender melhor forma de construir um site, este tutorial de AngularJS é um grande investimento de 15 minutos para aprender.
É Fácil construir meu website com Angular?
Sim. Atualmente uma pessoa criativa, mesmo com um modesto conhecimento de HTML, CSS e Javascript pode construir um site adequado e contemporâneo “single page”. Profissionais estão trabalhando juntos para resolver todos os problemas comuns de desenvolvimento web através da construção de soluções modulares, reutilizáveis. Estes projetos de código aberto colocam ferramentas simples e poderosas nas mãos ágeis de pessoas criativas. Ferramentas poderosas como AngularJS.
Vamos começar?
Uma empresa local, EmpresaSA, pediu-nos para construir um novo site.
As áreas básicas serão:
- Páginas
- Home
- Serviços
- Preço
- Sobre
- FAQ
- Contato
Para exemplificarmos de uma forma mais objetiva, vamos implementar um tema de site gratuito com base em Bootstrap.
Para este exemplo vamos usar:
(baixado gratuitamente do site http://startbootstrap.com)
Realizaremos o download do modelo do site e vamos descompactá-lo. A estrutura do arquivo original é como se poderia esperar, em tal modelo de site. Temos uma pasta css, pasta js, e uma variedade de arquivos de html.
Melhores Práticas: Por que nos importamos?
Vamos nos concentrar em index.html por um momento. O que nós aspiramos para nossa index.html ser? Mas qual é a melhor prática, e por que devemos nos preocupar?
Veja como o index.html fica no navegador:
Há a navegação em menus (na parte superior), e também no conteúdo geral da página. Tudo parece bem .. certo?
Bom Código vs Código Ruim
Nos bastidores, este código gratuito é uma bagunça. Se usarmos este modelo de site como está, a desorganização vai continuar forçando-nos a fazer um trabalho extra, criando arrasto desnecessário para todos os programadores que trabalham neste projeto, durante o tempo que ele permanecer online.
O problema é que este e qualquer outro arquivo .html neste tema gratuito (ex: about.html, services.html, etc.) contém uma cópia extra de cada parte do site!
Isso é uma enorme quantidade de HTML repetido. E uma regra do desenvolvimento web contemporâneo, que trouxe um aumento significativo de qualidade em toda a indústria é: NÃO repetir-se.
AngularJS é uma Grande Solução.
Angular é o caminho mais rápido para desenvolver, desde o website mais simples até à Aplicação mais complexa. Sonhamos com um index.html que funcione como um padrão para todo o projeto, a fim de nos ajudar a evitar a repetição de código em todos os outros arquivos html. Neste sonho, poderíamos alterar um grande elemento do site (como o menu de navegação no topo da página), com uma única linha de código, e alterar a sua aparência em todas as páginas do site de uma vez!
Melhorando o Projeto
Vamos criar um novo projeto/pasta (EmpresaSA), copiar as pastas do modelo que baixamos acima: (css, js, fonts, img e templates) e criar um novo arquivo index.html conforme mostrado abaixo.
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<!DOCTYPE html> <html> <head lang="br"> <meta charset="UTF-8"> <title>EmpresaSA</title> <link rel="stylesheet" href="css/bootstrap.min.css"/> <link rel="stylesheet" href="css/business-casual.css"/> <script src="js/jquery.js"></script> <script src="js/bootstrap.min.js"></script> <!-- aqui colocaremos posteriormente a chamada para o angular --> </head> <body> <!-- futuramente nosso conteudo ficará aqui --> <!-- outros scripts que criaremos ficarão aqui --> </body> </html> |
O que exatamente é AngularJS?
O Google descreve Angular como:
“O HTML teria sido, se tivesse sido projetado para a construção de web-apps”.
Angular traz o HTML (DOM) para a vida; Nossa página vai nascer interativa, sem a confusão de ter que escrever código para cada aspecto (por exemplo, modelos de carga sub-página, ou preencher listas de itens de dados), que são na verdade, relativamente fáceis de dizer, em linguagem simples.
Implementando os HTMLs
Como qualquer boa dependência, temos o angular com apenas uma linha. Nós adicionamos esta linha, abaixo da nossa marcação “aqui colocaremos posteriormente a chamada para o angular” index.html:
1 2 |
<!-- aqui colocaremos posteriormente a chamada para o angular --> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.min.js"></script> |
Provavelmente o elemento mais óbvio que gostaríamos de unificar é o menu de navegação. Quase todos os sites ou aplicativos o possuem. Vamos sonhar grande, e criar um modelos de arquivo header.html que contém apenas o menu de navegação HTML, sem qualquer outra coisa no arquivo. (o arquivo será criado na pasta templates)
Além disso, não vamos repetir a nós mesmos! Vamos remover todas as outras cópias do HTML do menu de navegação de todos os outros arquivos .html em nosso site.
Aqui está o nosso arquivo final templates/header.html:
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 |
<!-- Nome da empresa ou titulo do site --> <div class="brand">EmpresaSA</div> <!-- Endereço da empresa ou subtitulo do site --> <div class="address-bar">3481 Melrose Place | Beverly Hills, CA 90210 | 123.456.7890</div> <!-- Navigation --> <nav class="navbar navbar-default" role="navigation"> <div class="container"> <!-- aparecerá somente em dispositivos mobile --> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <!-- Nome da empresa ou titulo do site para os dispositivos mobile --> <a class="navbar-brand" href="index.html">EmpresaSA</a> </div> <!-- nossos menu --> <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> <ul class="nav navbar-nav"> <!-- cada linha é um item do menu --> <li><a href="#/servicos">Serviços</a></li> <li><a href="#/precos">Preços</a></li> <li><a href="#/sobre">Sobre</a></li> </ul> </div> <!-- /.navbar-collapse --> </div> <!-- /.container --> </nav> |
Agora vamos criar os templates das páginas do modelo que baixamos anteriormente, retirando tudo que não nos interessa, mantendo apenas o conteúdo, conforme abaixo:
templates/home.html:
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
<div class="row"> <div class="box"> <div class="col-lg-12 text-center"> <div id="carousel-example-generic" class="carousel slide"> <!-- Indicators --> <ol class="carousel-indicators hidden-xs"> <li data-target="#carousel-example-generic" data-slide-to="0" class="active"></li> <li data-target="#carousel-example-generic" data-slide-to="1"></li> <li data-target="#carousel-example-generic" data-slide-to="2"></li> </ol> <!-- Wrapper for slides --> <div class="carousel-inner"> <div class="item active"> <img class="img-responsive img-full" src="img/slide-1.jpg" alt=""> </div> <div class="item"> <img class="img-responsive img-full" src="img/slide-2.jpg" alt=""> </div> <div class="item"> <img class="img-responsive img-full" src="img/slide-3.jpg" alt=""> </div> </div> <!-- Controls --> <a class="left carousel-control" href="" data-target="#carousel-example-generic" data-slide="prev"> <span class="icon-prev"></span> </a> <a class="right carousel-control" href="" data-target="#carousel-example-generic" data-slide="next"> <span class="icon-next"></span> </a> </div> <h2 class="brand-before"> <small>Welcome to</small> </h2> <h1 class="brand-name">Business Casual</h1> <hr class="tagline-divider"> <h2> <small>By <strong>Start Bootstrap</strong> </small> </h2> </div> </div> </div> <div class="row"> <div class="box"> <div class="col-lg-12"> <hr> <h2 class="intro-text text-center">Build a website <strong>worth visiting</strong> </h2> <hr> <img class="img-responsive img-border img-left" src="img/intro-pic.jpg" alt=""> <hr class="visible-xs"> <p>The boxes used in this template are nested inbetween a normal Bootstrap row and the start of your column layout. The boxes will be full-width boxes, so if you want to make them smaller then you will need to customize.</p> <p>A huge thanks to <a href="http://join.deathtothestockphoto.com/" target="_blank">Death to the Stock Photo</a> for allowing us to use the beautiful photos that make this template really come to life. When using this template, make sure your photos are decent. Also make sure that the file size on your photos is kept to a minumum to keep load times to a minimum.</p> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc placerat diam quis nisl vestibulum dignissim. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> </div> </div> </div> <div class="row"> <div class="box"> <div class="col-lg-12"> <hr> <h2 class="intro-text text-center">Beautiful boxes <strong>to showcase your content</strong> </h2> <hr> <p>Use as many boxes as you like, and put anything you want in them! They are great for just about anything, the sky's the limit!</p> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc placerat diam quis nisl vestibulum dignissim. In hac habitasse platea dictumst. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p> </div> </div> </div> |
templates/sobre.html:
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 |
<div class="row"> <div class="box"> <div class="col-lg-12"> <hr> <h2 class="intro-text text-center">About <strong>business casual</strong> </h2> <hr> </div> <div class="col-md-6"> <img class="img-responsive img-border-left" src="img/slide-2.jpg" alt=""> </div> <div class="col-md-6"> <p>This is a great place to introduce your company or project and describe what you do.</p> <p>Lid est laborum dolo rumes fugats untras. Etharums ser quidem rerum facilis dolores nemis omnis fugats vitaes nemo minima rerums unsers sadips amets.</p> <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p> </div> <div class="clearfix"></div> </div> </div> <div class="row"> <div class="box"> <div class="col-lg-12"> <hr> <h2 class="intro-text text-center">Our <strong>Team</strong> </h2> <hr> </div> <div class="col-sm-4 text-center"> <img class="img-responsive" src="http://placehold.it/750x450" alt=""> <h3>John Smith <small>Job Title</small> </h3> </div> <div class="col-sm-4 text-center"> <img class="img-responsive" src="http://placehold.it/750x450" alt=""> <h3>John Smith <small>Job Title</small> </h3> </div> <div class="col-sm-4 text-center"> <img class="img-responsive" src="http://placehold.it/750x450" alt=""> <h3>John Smith <small>Job Title</small> </h3> </div> <div class="clearfix"></div> </div> </div> |
templates/precos.html:
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
<div class="row"> <div class="box"> <div class="col-lg-12"> <hr> <h2 class="intro-text text-center"> Pricing Table <strong>Our Pricing Options</strong> </h2> <hr> </div> </div> </div> <div class="row"> <div class="box"> <div class="col-sm-3"> <div class="panel panel-default text-center"> <div class="panel-heading"> <strong>Basic</strong> </div> <div class="panel-body"> <h3 class="panel-title price">$9 <span class="price-cents">99</span> <span class="price-month">mo.</span> </h3> </div> <ul class="list-group"> <li class="list-group-item">5 Projects</li> <li class="list-group-item">5 GB of Storage</li> <li class="list-group-item">Up to 100 Users</li> <li class="list-group-item">10 GB Bandwidth</li> <li class="list-group-item">Security Suite</li> <li class="list-group-item"><a class="btn btn-primary">Sign Up Now!</a> </li> </ul> </div> </div> <div class="col-sm-3"> <div class="panel panel-default text-center"> <div class="panel-heading"> <strong>Plus</strong> </div> <div class="panel-body"> <h3 class="panel-title price">$19 <span class="price-cents">99</span> <span class="price-month">mo.</span> </h3> </div> <ul class="list-group"> <li class="list-group-item">10 Projects</li> <li class="list-group-item">10 GB of Storage</li> <li class="list-group-item">Up to 250 Users</li> <li class="list-group-item">25 GB Bandwidth</li> <li class="list-group-item">Security Suite</li> <li class="list-group-item"><a class="btn btn-primary">Sign Up Now!</a> </li> </ul> </div> </div> <div class="col-sm-3"> <div class="panel panel-default text-center"> <div class="panel-heading"> <strong>Premium <span class="label label-success">Best Value!</span></strong> </div> <div class="panel-body"> <h3 class="panel-title price">$29 <span class="price-cents">99</span> <span class="price-month">mo.</span> </h3> </div> <ul class="list-group"> <li class="list-group-item">Unlimited</li> <li class="list-group-item">50 GB of Storage</li> <li class="list-group-item">Up to 1000 Users</li> <li class="list-group-item">100 GB Bandwidth</li> <li class="list-group-item">Security Suite</li> <li class="list-group-item"><a class="btn btn-primary">Sign Up Now!</a> </li> </ul> </div> </div> <div class="col-sm-3"> <div class="panel panel-default text-center"> <div class="panel-heading"> <strong>Ultimate</strong> </div> <div class="panel-body"> <h3 class="panel-title price">$49 <span class="price-cents">99</span> <span class="price-month">mo.</span> </h3> </div> <ul class="list-group"> <li class="list-group-item">Unlimited</li> <li class="list-group-item">150 GB of Storage</li> <li class="list-group-item">Unlimited</li> <li class="list-group-item">500 GB Bandwidth</li> <li class="list-group-item">Security Suite</li> <li class="list-group-item"><a class="btn btn-primary">Sign Up Now!</a> </li> </ul> </div> </div> </div> </div> |
templates/servicos.html:
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 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
<div class="row"> <div class="box"> <div class="col-lg-12"> <hr> <h2 class="intro-text text-center"> Services <strong>What We Do</strong> </h2> <hr> </div> <img class="img-responsive" src="http://placehold.it/1200x300"> </div> </div> <!-- /.row --> <!-- Service Paragraphs --> <div class="row"> <div class="box"> <div class="col-md-8"> <div class="col-lg-12"> <hr> <h2 class="intro-text text-center"> Our Premium Services </h2> <hr> </div> <p>Lid est laborum dolo rumes fugats untras. Etharums ser quidem rerum facilis dolores nemis omnis fugats vitaes nemo minima rerums unsers sadips amets. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p> </div> <div class="col-md-4"> <div class="col-lg-12"> <hr> <h2 class="intro-text text-center"> Something More </h2> <hr> </div> <h2 class="page-header">Something More</h2> <p>Etharums ser quidem rerum facilis dolores nemis omnis fugats vitaes nemo minima rerums unsers sadips amets.</p> <a class="btn btn-primary" href="#">Click Me!</a> </div> </div> </div> <!-- /.row --> <!-- Service images --> <div class="row"> <div class="box"> <div class="col-lg-12"> <hr> <h2 class="intro-text text-center"> Service Images </h2> <hr> </div> <div class="col-sm-4"> <img class="img-responsive" src="http://placehold.it/750x450"> <h3>Service One</h3> <p>Service one description. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc placerat diam quis nisl vestibulum dignissim. In hac habitasse platea dictumst.</p> <a class="btn btn-link btn-sm pull-right">More <i class="fa fa-angle-right"></i></a> </div> <div class="col-sm-4"> <img class="img-responsive" src="http://placehold.it/750x450"> <h3>Service Two</h3> <p>Service two description. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc placerat diam quis nisl vestibulum dignissim. In hac habitasse platea dictumst.</p> <a class="btn btn-link btn-sm pull-right">More <i class="fa fa-angle-right"></i></a> </div> <div class="col-sm-4"> <img class="img-responsive" src="http://placehold.it/750x450"> <h3>Service Three</h3> <p>Service three description. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc placerat diam quis nisl vestibulum dignissim. In hac habitasse platea dictumst.</p> <a class="btn btn-link btn-sm pull-right">More <i class="fa fa-angle-right"></i></a> </div> </div> </div> |
templates/footer.html:
1 2 3 4 5 6 7 8 9 |
<footer> <div class="container"> <div class="row"> <div class="col-lg-12 text-center"> <p>Copyright © Your Website 2014</p> </div> </div> </div> </footer> |
Adicionando Diretivas do AngularJS
O Rodrigo Branas define as diretivas assim:
Diretivas são extensões da linguagem HTML que permitem a implementação de novos comportamentos de forma declarativa.
A primeira diretiva que precisamos inserir é a ng-app
que vai iniciar o AngularJS, avisando que aquele pedaço de HTML é a minha aplicação e que ele vai apenas funcionar naquele escopo. Nesse nosso projeto, eu inseri ng-app
no body da página.
index.html
1 |
<body ng-app="website"> |
Agora nós iremos adicionar outra diretiva do Angular o ng-include que serve para adicionarmos um trecho HTML de outro arquivo.
index.html
1 2 3 4 |
<!-- futuramente nosso conteudo ficará aqui --> <div ng-include='"templates/header.html"'></div> <div class="container" ng-view="conteudo"></div> <div ng-include='"templates/footer.html"'></div> |
Além disso também adicionamos a diretiva ng-view que será utilizado para adicionar os conteúdos das nossas páginas, isso será abordado em breve, mas antes precisaremos incluir logo após “outros scripts que criaremos ficarão aqui”, o angular-route que será utilizado para gerenciar as rotas que serão carregados na nossa ng-view.
E também vamos precisar do nosso javascript que iremos desenvolver em seguida.
1 2 3 |
<!-- outros scripts que criaremos ficarão aqui --> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular-route.min.js"></script> <script src="js/main.js"></script> |
Configurando a aplicação
É aqui que o show acontece! No arquivo main.js, primeiro carregamos o módulo ngRoute que é usado para deep-linking URLs para controllers e views. Este módulo observa qual é url ($location.url()) e tenta mapear o caminho de acordo com alguma rota pré-definida, assim ele consegue executar o controller e a view correspondente para cada url.
Para setarmos uma configuração no AngularJS, precisamos usar a função config, que pode receber diversas propriedades já existentes do angular.
js/main.js:
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 |
/** * Inicializamos o angular.module com o mesmo nome que definimos na diretiva ng-app * E incluímos a dependência do ngRoute */ var app = angular.module('website', [ 'ngRoute' ]); /** * Como possuímos a variavel app definida acima com a inicialização do Angular * através do app.config conseguimos criar as configurações * definimos que essa configuração depende do $routeProvider e usamos na function($routeProvider) */ app.config(['$routeProvider', function ($routeProvider) { $routeProvider // aqui dizemos quando estivernos na url / vamos carregar o conteúdo da pagina inicila a home // no segundo parametro definimos um objeto contendo o templateUrl da nossa pagina home e o controller que irá // preparar o conteudo e processar outros eventos da página que veremos posteriormente .when("/", {templateUrl: "templates/home.html", controller: "HomeCtrl"}) // configuração das rotas bem parecidas para as outras paginas .when("/sobre", {templateUrl: "templates/sobre.html", controller: "SobreCtrl"}) .when("/servicos", {templateUrl: "templates/servicos.html", controller: "ServicosCtrl"}) .when("/precos", {templateUrl: "templates/precos.html", controller: "PrecosCtrl"}) /* aqui você pode adicionar rotas para outras paginas que desejar criar */ // por último dizemos se nenhuma url digitada for encontrada mostramos a página 404 que não existe no nosso servidor .otherwise("/404", {templateUrl: "templates/404.html"}); }]); |
O $routeProvider é usado para configurar as rotas, que é exatamente o que estamos fazendo, quando usamos o .when(), definimos a rota (url) e depois um objeto com o templateUrl (url da view) e qual nome do controller correspondente.
Definindo os controllers
Para criar um controller no angular, podemos usar a instância do módulo, que definimos anteriormente como “app”, deste modo definimos um controller mais modular (é como prefiro :]) ou de forma tradicional como sempre criamos funções no JavaScript (function HomeCtrl($scope, $location){ //do stuff… }).
Por ser apenas um exemplo, coloquei todos meus controllers no mesmo arquivo, mas caso prefira, poderá colocar em arquivos diferentes. Só não esqueça de “linka-los” à index.
Criaremos o primeiro controller com o nome de ‘HomeCtrl’, igual ao que definimos nas rotas acima, estamos passando para ele dois parâmetros, $scope e $location, já definidos no Angular.
continuação do js/main.js:
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 |
/* * Controller utilizado nesse exemplo para ativar a galeria e tooltips */ app.controller('HomeCtrl', function ($scope, $location) { // Activates the Carousel $('.carousel').carousel({ interval: 5000 }); // Activates Tooltips for Social Links $('.tooltip-social').tooltip({ selector: "a[data-toggle=tooltip]" }) }); app.controller('SobreCtrl', function ($scope, $location) { }); app.controller('ServicosCtrl', function ($scope, $location) { }); app.controller('PrecosCtrl', function ($scope, $location) { }); |
Finalizando
Pronto! Temos um pequeno site utilizando o AngularJS. Abaixo você poderá baixar a versão final de nosso tutorial.
Em uma próxima publicação mostraremos a criação da página de contato e o envio de email utilizando o PHP para envio. E outros recursos que o AngularJS nos oferece.