Porque utilizar AngularJS no seu próximo projeto

Vamos começar pela definição: AngularJS é um framework JavaScript para construção de aplicações web dinâmicas, comumente referenciado como um framework MVC client side. Essa definição não está errada, mas o fato é que MVC é um padrão para dividir uma aplicação em diferentes partes (modelo, visão e controle), cada uma com suas respectivas responsabilidades. O AngularJS  não implementa um MVC na sua forma tradicional, mas algo próximo de um MVVM (Model – View – ViewModel). Logo, seu próprio time de desenvolvimento resolveu batizá-lo, carinhosamente, de um framework MVW  – Model View Whatever. Bem, o time de desenvolvimento do Angular dispensa apresentação, ele nasceu e é mantido por uma empresa que entende de web, o Google.

“AngularJS – Superheroic JavaScript MVW Framework”

A principal característica do AngularJS é que ele funciona como uma extensão do HTML, diferente de outros frameworks JavaScript, não é necessário manipular o DOM. Isso possibilita a criação de um front end mais organizado e sem a necessidade de manipular “html + dados”.

Suas principais características são:

  • Two-way Data binding
  • Injeção de Dependências
  • Criação de diretivas (Extensão do HTML)
  • Modularização e reuso (Controllers, Services e Filters)
  • Testabilidade

Basicão


<html ng-app>
 <head>
     <title>AngularJS</title>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>
 </head>
 <body>
     <p>Meu nome é: {{ nome }}</p>
     <input type="text" ng-model="nome">
 </body>
</html> 

Este é o exemplo mais básico em AngularJS. A diretiva ng-app na tag <html> inicializa a aplicação e define esta tag como o elemento root da aplicação, tudo a partir dela pode ser gerenciado pelo Angular. Ao digitar algo no input o nome será atualizado em realtime na tela. Essa mágica é chamada de Two-way data binding. Qualquer interação na view será refletida no modelo e vice-versa, isso é feito através do objeto $scope, criado automaticamente pelo angular. A propriedade ng-model é responsável por fazer o canal de comunicação e a sintaxe utilizada é o “bigode-bigode”: {{ atributo }}. Note que até aqui não escrevemos nenhum código JavaScript.

Controllers

Para entender como é feito o vínculo da view com o modelo, e como o angular permite organizamos nossa aplicação com a chamada de Controllers, segue o código a seguir:

cervejas.html


<div ng-controller="CervejaController">
 <form name="form">
     <input type="text" placeholder="Cerveja" ng-model="cerveja.nome">
     <input type="text" placeholder="Cervejaria" ng-model="cerveja.cervejaria">
     <button ng-click="adicionar()">Adicionar</button>
 </form>
 <table>
 <thead>
     <tr>
         <th>Cerveja</th>
         <th>Cervejaria</th>
     </tr>
 </thead>
 <tbody>
     <tr ng-repeat="cerveja in cervejas">
         <td>{{ cerveja.nome }}</td>
         <td>{{ cerveja.cervejaria }}</td>
     </tr>
 </tbody>
 </table>
</div> 

CervejaController.js


function CervejaController($scope) {
 $scope.cervejas = [ { nome : 'Cerpinha', cervejaria : 'Cerpa'},
                     { nome : 'Tijuca', cervejaria : 'Cerpa' } ];

 $scope.adicionar = function() {
     $scope.cervejas.push({nome : $scope.cerveja.nome,
                           cervejaria : $scope.cerveja.cervejaria});
     $scope.limpar();
 };

 $scope.limpar = function() {
     $scope.cerveja = {nome: '', cervejaria: ''};
 };
}

A diretiva ng-controller vincula um elemento html com um Controller JavaScript, no caso CervejaController. Tudo a partir desta div pode ser controlado por este Controller. O button chama através da diretiva ng-click a função adicionar(), definida dentro do nosso Controller. Esta função adiciona uma nova cerveja na listagem e limpa os campos do formulário. Ao iniciar o controller, por padrão é adicionada duas cervejas na listagem, também poderíamos usar a diretiva ng-init neste caso. Note que a variável $scope foi recebida como argumento do Controller. Este é um exemplo de injeção de dependência feito automaticamente pelo AngularJS, um dos principais recursos do framework.

Outra diretiva interessante presente neste exemplo é a ng-repeat, que permite iterar em listas de forma bem simples e intuitiva, no formato <elemento> in <coleção>.

Filters

Outro recurso muito interessante e nativo do framework é a aplicação de filters. Os filtros servem para transformar o resultado de uma expressão, aplicando algum tipo de formatação ou restrição nos dados. Segue o exemplo:


<h2>Busca</h2>
Cerveja: <input ng-model="search.nome">
Cervejaria: <input ng-model="search.cervejaria">
<table>
 <thead>
    <tr>
        <th><a href="">Cerveja</a></th>
        <th>Cervejaria</th>
    </tr>
  </thead>
 <tbody>
    <tr ng-repeat="cerveja in cervejas | filter:search | orderBy:'nome'">
        <td>{{ cerveja.nome | uppercase }}</td>
        <td>{{ cerveja.cervejaria }}</td>
    </tr>
 </tbody>
</table> 

A sintaxe dos filtros funciona com a inclusão de um pipeline “|” dentro da expressão. No exemplo foi adicionado dois inputs, para filtrar por nome e por cervejaria, através do objeto search, incorporado na diretiva ng-repeat: “filter:search”. Os filtros também suportam ordenação através da propriedade orderBy. Adicionalmente existem alguns filtros padrão no Angular, como uppercase, lowercase e date. Há também a possibilidade de criar filtros customizados da seguinte forma:


App.filter('meuFiltro', function() {
    return function(data) {
        return data;
    };
});

Services

O conceito de separação de responsabilidades está presente no AngularJS através da aplicação de Services. Basicamente, os serviços são funções javascript que devem executar funções específicas, bem definidas, de fácil manutenção e testáveis. Dessa forma é possível modularizar e reaproveitar serviços em diferentes controladores, por meio da injeção de dependências, da seguinte forma:


//app.js
var app = angular.module("app", []);

app.service('CervejaService', function(){
    this.remover = function(cervejas, cerveja) {
        var index = cervejas.indexOf(cerveja);
        cervejas.splice(index, 1);
    };
});

//CervejaController.js
function CervejaController($scope, CervejaService) {
    //...
    $scope.remover = function(cerveja) {
        CervejaService.remover($scope.cervejas, cerveja);
    };
}


//cervejas.html
<table>
    <thead>
        <tr>
            <th><a href="">Cerveja</a></th>
            <th>Cervejaria</th>
            <th></th>
        </tr>
     </thead>
     <tbody>
        <tr ng-repeat="cerveja in cervejas | filter:search | orderBy:'nome'">
             <td>{{ cerveja.nome | uppercase }}</td>
             <td>{{ cerveja.cervejaria }}</td>
             <td><button ng-click="remover(cerveja)">Remover</button></td>
        </tr>
     </tbody>
</table> 

Na primeira linha, é iniciado o módulo principal da aplicação, o primeiro argumento é o nome do módulo, o segundo é um lista de dependências externas que podem ser injetadas na aplicação, como plug-ins de controle de rotas, componentes de view, etc. Em seguida é definido o serviço CervejaService, nele implementamos uma função para remover uma cerveja de uma listagem, essa função pode ser usada em qualquer controller que injete este serviço. Para chamar a função de remoção, basta uma chamada via ng-click para a função remover(),definida no controller, para que o serviço seja invocado.

Jasmine

Graças a organização do código que o AngularJS nos proporciona, testá-lo se torna uma tarefa fácil. Para isso vamos usar o framework de teste Jasmine. Aliás, o próprio código do Angular é testado utilizando Jasmine. Precisamos importar apenas jasmine.js e o módulo de mocks do angular.


beforeEach(module('app'));
describe('CervejaController', function () {

    it('deve definir uma cerveja padrao com nome e cervejaria vazias', inject(function ($controller) {
        var scope = {};
        var ctrl = $controller('CervejaController', { $scope: scope });

        expect(scope.cerveja.nome).toBe('');
        expect(scope.cerveja.cervejaria).toBe('');
    }));

    it('deve iniciar com duas cervejas carregadas', inject(function ($controller) {
        var scope = {};
        var ctrl = $controller('CervejaController', { $scope: scope });

        expect(scope.cervejas.length).toBe(2);
    }));

    it('deve limpar uma cerveja', inject(function ($controller) {
        var scope = {};
        var ctrl = $controller('CervejaController', { $scope: scope });

        scope.cerveja = {nome: 'Cerpinha', cervejaria: 'Cerpa'};
        scope.limpar(); 

        expect(scope.cerveja.nome).toBe('');
        expect(scope.cerveja.cervejaria).toBe('');
    }));
});

A função beforeEach carrega o módulo antes de iniciarmos o teste do CervejaController. Basicamente foram definidos três testes, os dois primeiros testam o estado inicial do controller, o terceiro testa a função limpar. A função expect é responsável por fazer a asserção de nossos testes.

Daria para escrever um artigo só para os detalhes da implementação de testes com Jasmine e suas diferentes abordagens de cobertura dentro de aplicações com AngularJS.

Conclusões

As possibilidades do AngularJS não se esgotam aqui, existem vários recursos que não foram abordados. Mas o que foi apresentado serve de base pra você considerar utilizar este poderoso framework no seu próximo projeto.

Todo código apresentado aqui está disponível no github.

Tá Safo! visita Chaordic

IMG-20141105-WA0009

Selfie na Chaordic: Fábio Lima, Joel Marques, Anderson Nielson, Marcus Paulo, Fernanda Melina e Ramon Rabello (Esquerda para direita)

Aproveitando a ida da Comunidade Tá Safo! ao Agile Brazil desse ano, que aconteceu em Florianópolis, conseguimos agendar uma visita à Chaordic, facilitada pelo nosso amigo Jaime Schettini. A visita ocorreu dia 05 de novembro. Fomos recepcionados por Anderson Nielson (Peopleware Director) e, logo na chegada, ficamos surpresos. Na sala de recepção, havia um armário colorido e sapateiras. Estranho, não?! Futuramente explicarei a história do porquê.

Continuar lendo

Diário de um projeto: PCMobile

Dando sequência à série “Diário de um projeto”, apresentamos agora a história do primeiro aplicativo Android criado pela Comunidade Tá safo: o Palestras Coletivas Mobile, ou simplesmente PCMobile.

PCMobile é o cliente móvel para a plataforma Palestras Coletivas.  O objetivo do projeto é trazer o usuário informado sobre as atualizações de eventos de tecnologia, palestras e workshops que estejam acontecendo na cidade, divulgadas pelo site Palestras Coletivas.

Tela do Palestras Coletivas Mobile

Palestras Coletivas Mobile no Google Play

Motivação histórica

Muito além de buscar ser uma solução para um problema real, todo o esforço de criação da plataforma Palestras Coletivas e abertura de seu código-fonte também representou uma injeção de ânimo e uma motivação para resgate do espírito de colaboração mútua e compartilhamento de conhecimento que era comum nos primórdios da comunidade Tá safo.

Continuar lendo

Diário de um projeto: Palestras Coletivas

Você algumas vezes já sentiu estar fazendo algumas coisas no automático, sem saber exatamente porque você as faz?

O Tá safo inicia aqui uma nova série de artigos sobre os projetos da comunidade para apresentar como e porque eles surgiram, as discussões que motivam suas evoluções e os detalhes técnicos que podem balizar como os mesmo estão evoluindo.  Neste primeiro artigo, apresentamos o Palestras Coletivas.

O Palestras Coletivas é a plataforma online para marcação e divulgação de eventos relacionados à tecnologia em geral do Tá safo!

Homepage do Palestras Coletivas

Palestras Coletivas

Motivação histórica

Para entender um pouco melhor o contexto da criação do Palestras Coletivas é necessário compreender brevemente um pouco da própria história do Tá safo!

Continuar lendo