Tutorial Inicial em Angular 1x

Preparando o ambiente 

Nosso foco é aprender Angular, porém alguns recursos do framework necessitam de um servidor web rodando localmente em sua máquina. Para que você não perca o foco do Angular e não caia em questões de infraestrutura que dizem respeito a um servidor web, disponibilizamos projeto helloworld com tudo necessário para subir um servidor web localmente, inclusive com os arquivos do angular já baixados.
É importante destacar que o uso do projeto inicial helloworld não é opcional, pois ele já possui registrado todos os endpoints que serão consumidos pela nossa aplicação em Angular. Além disso, para que o servidor funcione, é necessário ter o Node.js instalado em sua máquina.
Node.js é um ambiente JavaScript multiplataforma disponível para Linux, Mac e Windows. Para instalá-lo, siga as instruções abaixo referentes a sua plataforma:
Linux (Ubuntu)
No Ubuntu, através do terminal (permissão de administrador necessária) execute o comando abaixo:
sudo apt-get install -y nodejs

ATENÇÃO: em algumas distribuições Linux, pode haver um conflito de nomes quando o Node é instalado pelo apt-get. Neste caso específico, no lugar do binário ser node, ele passa a se chamar nodejs. Isso gera problemas, pois a instrução npm start não funcionará, pois ela procura o binário node e não nodejs. Para resolver, use a seguinte instrução no terminal para subir o servidor:

nodejs server
Windows
Baixe o instalador clicando no grande botão install diretamente da página do Node.js. Durante a instalação, você apenas clicará botões para continuar o assistente. Não troque a pasta padrão do Node.js durante a instalação a não ser que você saiba exatamente o que está fazendo.

MAC

homebrew é a maneira mais recomendada para instalar o Node.js em sua máquina, através do comando:

brew update
brew install node

Não usa homebrew? Sem problema, baixe o instalador clicando no grande botão install diretamente da página do Node.js.
Rodando o servidor

Depois do Node.js ter sido instalado, dentro da pasta do projeto helloworld que você descompactou anteriormente, busque todas as dependências do projeto através do seu terminal (prompt de comando, no caso do Windows) favorito com o comando.

npm install

ATENÇÃO USUÁRIOS DE WINDOWS: se por acaso mensagem de erro forem exibidas, procure pelo texto npm ERR! self signed certificate. Se ele existir, isso indica um problema no certificado do seu roteador (proxy). Não se preocupe, basta rodar o comando no terminal npm set strict-ssl false que resolvera este problema.
Em menos de um minuto, todas as dependências para rodar o servidor terão sido baixadas. Para subi-lo utilizamos o comando:
npm start

Repare que seu terminal ficará aguardando indefinidamente, sinal de que o servidor está escutando. Agora é só abrir o navegador no endereço http://localhost:3000. Uma página de boas-vindas será exibida. 

Quando desenvolvemos no server-side, organizamos nosso código em camadas para facilitar a manutenção, o reaproveitamento e a legibilidade de nosso código. É muito comum aplicarmos o modelo MVC (Model, View, Controller), que consiste na separação de tarefas, facilitando assim a reescrita de alguma parte e a manutenção do código.
Porém, não é raro o mesmo desenvolvedor deixar de lado essas práticas quando codifica no client-side. Mesmo aqueles que procuram organizar melhor seu código acabam criando soluções caseiras que nem sempre são bem documentadas.
Tendo como base este cenário, frameworks MVC client-side foram criados. Entre eles temos o BackboneEmberKnockoutCanJSBatman, entre outros.

Angular, o framework MVC da Google


Um framework MVC no lado do cliente que tem ganhado muita atenção da comunidade é o Angular. Criado como um projeto interno da Google e liberado para o público em 2009, ele tem como foco a criação de Single Page Applications (SPA’s). Este tipo de aplicação não recarrega a página durante seu uso, dando uma experiência mais fluída para o usuário. Não se preocupe se você é novo para este tipo de aplicação, você terá a oportunidade de entender melhor seus conceitos ao longo do treinamento.

Por onde começar?


Angular é um framework que roda no lado do cliente, sendo assim, como qualquer outro script, deve ser importado na página que desejamos eleger como principal da aplicação, em nosso caso, a página já existente, index.html, que está salva dentro da pasta helloworld/public. Primeiramente vamos dar uma olhada em sua estrutura:

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="pt-br">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Hello World</title>
        <link rel="stylesheet" href="css/bootstrap.min.css">
        <link rel="stylesheet" href="css/bootstrap-theme.min.css">
    </head>
    <body>
        <div class="container">
            <h1 class="text-center">Hello World!</h1>
        </div> <!-- fim container -->        
    </body>
</html>

Repare que a página já importa o CSS do Bootstrap. Se você ainda não o conhece, fique sabendo que ele permite aplicar um visual profissional em nosso projeto, com zero de esforço, apenas adicionando classes declaradas em seu arquivo CSS. Que classes são essas? A classe container centraliza todo conteúdo da página e a text-center centraliza um elemento do tipo block, em nosso caso, a tag h1.
Agora que você já entendeu o papel do Bootstrap em nosso projeto, já podemos continuar. Todas as páginas, bibliotecas, scripts e qualquer outro arquivo dentro da pasta helloworld/public serão acessíveis através do seu navegador, inclusive já temos dentro da pasta helloworld/public/js/lib todos os arquivos do Angular que importaremos à medida que formos precisando. Vamos importar o script angular.min.js, o core do Angular dentro da tag head:

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="pt-br">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Hello World</title>
        <link rel="stylesheet" href="css/bootstrap.min.css">
        <link rel="stylesheet" href="css/bootstrap-theme.min.css">
        <script src="js/lib/angular.min.js"></script>
    </head>
    <body>
        <div class="container">
            <h1 class="text-center">Hello World!</h1>
        </div> <!-- fim container -->        
    </body>
</html>
Pronto, mas ainda não escrevemos um código que utiliza o Angular! Para fazermos isso, primeiro precisamos criar um módulo.

Criando o alicerce da nossa aplicação, o módulo principal

A história é a seguinte: o framework nos ajuda a separar nosso código em pequenos grupos de código que podem ser combinados e reaproveitados quando necessário, esses grupos são chamados de módulos. Uma aplicação pode ter um, dez ou até mesmo mais de cinquenta módulos, tudo dependerá da complexidade da aplicação. Porém, há sempre um módulo que é o primeiro a ser inicializado assim que sua página é carregada pela primeira vez, inclusive ele também é o responsável pelo carregamento de outros módulos de que sua aplicação precisa para funcionar. É este que criaremos agora!
Vamos criar o arquivo public/js/main.js e mesmo sem escrever qualquer linha de código, vamos importá-lo sem demora na página index.html, abaixo da importação do core do Angular, para não corrermos o risco de esquecermos de importá-lo:

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="pt-br">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Hello World</title>
        <link rel="stylesheet" href="css/bootstrap.min.css">
        <link rel="stylesheet" href="css/bootstrap-theme.min.css">
        <script src="js/lib/angular.min.js"></script>
        <script src="js/main.js"></script>
    </head>
    <body>
        <div class="container">
            <h1 class="text-center">Hello World!</h1>
        </div> <!-- fim container -->        
    </body>
</html>

Pronto, e agora? Como criamos nosso módulo? Bem, o Angular disponibiliza para nós no escopo global o objeto angular que possui uma série de funções que nos permite interagir com o framework, entre elas a função module responsável pela criação de módulos.
Você deve estar pensando "Ok, entendi que é através desse objeto global que eu crio módulos e um monte de coisas do framework, mas escopo global não é algo ruim?". Preocupação justa, mas não se preocupe! Em uma aplicação bem-feita em Angular, este é o único objeto disponível globalmente, todo restante fica confinado dentro dos módulos do Angular! Com o tempo isso ficará ainda mais claro para você.
Criando o módulo principal da aplicação:
// public/js/main.js
 
angular.module('helloworld', []);

Acabamos de criar nosso primeiro módulo. Perceba que a função module recebe dois parâmetros. O primeiro é o nome do módulo que desejamos criar e o segundo é uma array com todos os módulos de que nosso módulo depende. Como não avançamos ainda com o projeto, não temos nenhuma dependência ainda, porém, você não deve omitir este parâmetro. Mais tarde você entenderá o que acontece quando ele é omitido.

Ensinando um truque novo para o navegador


Tudo certo, criamos nosso módulo, mas como o Angular saberá que deve carregá-lo? Será que importar o script public/js/main.js é suficiente?

Com certeza não!
Precisamos indicar em nossa página qual será o escopo de atuação do Angular, isto é, se ele gerenciará a página inteira ou apenas parte dela. Isso é importante, porque outro framework MVC pode estar sendo utilizado (algo raro, porém pode acontecer) e não queremos que o Angular bagunce seu trabalho.
Como apenas utilizaremos o Angular, gerenciaremos a página inteira, isto, a tag html e todos seus elementos filhos! Tudo bem, mas como faremos essa associação? Através do atributo ng-app:

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="pt-br" ng-app="helloworld">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Hello World</title>
        <link rel="stylesheet" href="css/bootstrap.min.css">
        <link rel="stylesheet" href="css/bootstrap-theme.min.css">
        <script src="js/lib/angular.min.js"></script>
        <script src="js/main.js"></script>
    </head>
    <body>
        <div class="container">
            <h1 class="text-center">Hello World!</h1>
        </div> <!-- fim container -->        
    </body>
</html>

Repare que o atributo ng-app tem como valor o nome do nosso módulo e não poderia ser diferente. Quando nossa página é carregada pela primeira vez o Angular encontrará esse atributo e carregará o módulo helloworld, tudo isso automaticamente, sem termos que nos preocupar em carregá-lo! É claro que se você esquecer de importar o arquivo main.js o Angular não será capaz de carregar o módulo, certo?

Ah, então isso é uma diretiva?


Agora, só uma coisa antes de continuarmos: o atributo ng-app existe no mundo HTML? Com certeza não, ele não faz parte da especificação da W3C. O "atributo" ng-app é na verdade uma diretiva do Angular.
Diretivas ampliam o vocabulário do navegador, ensinando-o novos truques. Nesse caso a diretiva ng-app fornece a capacidade de nossa página carregar/iniciar o módulo principal da aplicação. Aliás, não vamos mais usar o termo página, usaremos view, termo mais correto quando estamos no universo do Angular!

Nossa primeira página dinâmica

Legal, agora, com o servidor iniciado vamos acessar o endereço http://localhost:3000 e verificar o resultado. Como esperado, nada impressionante, pois apenas preparamos a infraestrutura mínima de uma aplicação em Angular, que nada faz. No máximo, podemos ver através do console do navegador todos os arquivos carregados:


Bom, vamos começar a dar um colorido para nossa view index.html. Vamos adicionar uma foto, você pode escolher a URL de uma específica, não precisa ser igual a minha. Na tag img, utilizaremos as classes img-responsive center-block para que ela escale corretamente nos mais diversos dispositivos:

<!DOCTYPE html>
<html lang="pt-br" ng-app="helloworld">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Hello World</title>
        <link rel="stylesheet" href="css/bootstrap.min.css">
        <link rel="stylesheet" href="css/bootstrap-theme.min.css">
        <script src="js/lib/angular.min.js"></script>
        <script src="js/main.js"></script>
    </head>
    <body>
        <div class="container">
            <h1 class="text-center">Hello World!</h1>
            <img class="img-responsive center-block" src="http://www.fundosanimais.com/Minis/leoes.jpg" alt="Leão">
        </div><!-- fim container -->
    </body>
</html>

Mas isso não impressiona, além do mais, se tivéssemos 100 imagens teríamos que repetir a tag img 100 vezes! Em nossa aplicação aprenderemos a cadastrar informações de imagens e a partir desses dados cadastrados montaremos dinamicamente uma lista de imagens! Só que antes de pensar em integração com o back-end, precisamos primeiro entender como o Angular fornece dados para a nossa view e como ela se constrói a partir desses dados.
Vamos realizar uma pequena mudança na tag img, alterando os atributos src e alt:

<!DOCTYPE html>
<html lang="pt-br" ng-app="helloworld">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Hello World</title>
        <link rel="stylesheet" href="css/bootstrap.min.css">
        <link rel="stylesheet" href="css/bootstrap-theme.min.css">
        <script src="js/lib/angular.min.js"></script>
        <script src="js/main.js"></script>
    </head>
    <body>
        <div class="container">
            <h1 class="text-center">Hello World!</h1>
            <img class="img-responsive center-block" src="{{foto.url}}" alt="{{foto.titulo}}">
        </div><!-- fim container -->
    </body>
</html>

A primeira coisa é entender que abrimos lacunas em nossa view index.html através da sintaxe {{ }}. Se temos uma view que agora possui lacunas, podemos chamá-la de template. Quando alguém envia um memorando para outra, raramente ela começa do zero, ou seja, ela adota um template, toda uma estrutura já pronta e seu único trabalho é preencher essas lacunas que variam de acordo com a situação. Isso se aplica no mundo Angular! O que acontece se visualizarmos nossa página agora? Nenhuma imagem será exibida e nenhum erro ocorrerá! Aliás, o termo lacuna é muito genérico, no mundo Angular usamos Angular Expression (AE). Todo {{ }} que encontrarmos chamaremos de AE. Combinado?
Quando temos um template que precisa de algum dado através de uma AE e não encontra, simplesmente aquela expressão fica em branco. Agora, a pergunta que não quer calar: quem, no modelo MVC é o responsável em disponibilizar dados para a views? Se você respondeu controller acertou!

Nosso primeiro controller

Precisamos criar um controller que disponibilize para a view o dado que ela precisa, no caso um objeto que contenha como chave o título e o endereço de uma foto, por exemplo { titulo: 'Leão', url : 'http://www.fundosanimais.com/Minis/leoes.jpg'}.
Lembra do nosso módulo principal da aplicação? Podemos criar um ou mais controllers diretamente nele, porém é uma boa prática declarar cada controller em arquivos separados, mesmo que eles façam parte do módulo helloworld. Vamos criar dentro de public/js/controllers/fotos-controller.js.
Criando nosso controller:
// public/js/controllers/fotos-controller.js
 
angular.module('helloworld').controller('FotosController', function() {
  // definição do controller aqui 
});

Veja que chamamos novamente angular.module, só que dessa vez sem passar o segundo parâmetro, o array vazio. Quando fazemos isso, indicamos que queremos acessar o módulo e não criar um novo. Faz todo sentido, se queremos que nosso controller faça parte do módulo helloworld. Em seguida encadeamos uma chamada à função controllerque recebe dois parâmetros. O primeiro é o nome do controller que estamos criando na convenção PascalCase, o segundo uma função que define o controller.
Sabemos que o controller deve fornecer o objeto foto para a view e que esse objeto deve conter as chaves titulo e url. Faremos isso agora!

// public/js/controllers/fotos-controller.js
 
angular.module('helloworld').controller('FotosController', function() {
 
    var foto = {
        titulo : 'Leão',
        url : 'http://www.fundosanimais.com/Minis/leoes.jpg'
    };
 
});

Excelente, agora precisamos importar o novo arquivo js que acabamos de criar em nossa view principal index.html:

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="pt-br" ng-app="helloworld">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Hello World</title>
        <link rel="stylesheet" href="css/bootstrap.min.css">
        <link rel="stylesheet" href="css/bootstrap-theme.min.css">
        <script src="js/lib/angular.min.js"></script>
        <script src="js/main.js"></script>
        <script src="js/controllers/fotos-controller.js"></script>
    </head>
    <body>
        <div class="container">
            <h1 class="text-center">Hello World!</h1>
 
             <img class="img-responsive center-block" src="{{foto.url}}" alt="{{foto.titulo}}">
 
        </div><!-- fim container -->
    </body>
</html>

Será que isso é suficiente? Não, precisamos indicar dentro da nossa view index.html qual fragmento será gerenciado pelo nosso controller. Angular permite associarmos diferentes controllers para diferentes partes de nossa view, uma maneira de separar responsabilidades. Porém, neste exemplo, queremos que o controller gerencie a tag body e todos os seus elementos filhos e fazemos isso através da diretiva ng-controller, que deve ter como valor o nome exato do controller que criamos:

<!DOCTYPE html>
<html lang="pt-br" ng-app="helloworld">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width">
        <title>Hello World</title>
        <link rel="stylesheet" href="css/bootstrap.min.css">
        <link rel="stylesheet" href="css/bootstrap-theme.min.css">
        <script src="js/lib/angular.min.js"></script>
        <script src="js/main.js"></script>
        <script src="js/controllers/fotos-controller.js"></script>
    </head>
    <body ng-controller="FotosController">
        <div class="container">
            <h1 class="text-center">Hello World!</h1>
 
             <img class="img-responsive center-block" src="{{foto.url}}" alt="{{foto.titulo}}">
 
        </div><!-- fim container -->
    </body>
</html>

Será que funciona? Visualizando no navegador, a imagem não é exibida e também não temos uma mensagem de erro. Por quê? O objeto foto não foi criado dentro do nosso controller? Sim, mas como ele foi declarado com var dentro de uma função, ele possui escopo privado. Ah, então para resolvermos vamos remover var, fazendo com que ele caia no escopo global? Nem pensar! Porém, o Angular disponibiliza uma ponte de ligação entre o controller e a view chamada $scope e tudo que for "pendurado" neste objeto será enxergado pela view. Mas como teremos acesso a esse objeto tão especial dentro do mundo Angular? Pedindo! Como? Recebendo-o na função que declara o controller:

angular.module('helloworld').controller('FotosController', function($scope) {
 
});

Angular encontra na declaração do controller $scope e sabe que tem que criar um para nós. Se tivéssemos escrito o nome do parâmetro de outra maneira, o framework não o criaria. Ou seja, Angular sabe o que deve buscar de sua infraestrutura de acordo com o nome do parâmetro que recebemos em nosso controller. Agora que já temos acesso à $scope, a ponte de ligação do controller com a view, podemos pendurar os dados da foto como sua propriedade.

angular.module('helloworld').controller('FotosController', function($scope) {
 
    $scope.foto = {
        titulo : 'Leão',
        url : 'http://www.fundosanimais.com/Minis/leoes.jpg'
    };
 
});

Lembre-se que tudo pendurado em $scope será acessível em nossa view, em nosso caso , através da angular expression. Duvida? Só testar e verificar o resultado.

Ah, isso é data binding?

Angular possui um termo apropriado para associação de um dado disponibilizado por um controller para a view: data binding(associação/ligação de dados). Qualquer alteração no dado do controller dispara uma atualização da view sem que o desenvolvedor tenha que se preocupar ou intervir no processo.

Excelente! Conseguimos um resultado semelhante ao que tínhamos antes, com a diferença de que agora a AE (Angular Expression) de nossa view foi processada com os dados fornecidos por FotosController. Pode parecer pouco, mas isso abre a porteira para que possamos avançar ainda mais no framework da Google.

Comentários

Postagens mais visitadas deste blog

MySQL & Segurança

HTML + CSS + BOOTSTRAP