Artigos

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

[code language=”html”]

<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>Meu nome é: {{ nome }}

<input type="text" ng-model="nome">
</body>
</html>

[/code]

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

[code language=”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>
[/code]

CervejaController.js

[code language=”javascript”]

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: ”};
};
}

[/code]

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:

[code language=”html”]
<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>
[/code]

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:

[code language=”javascript”]

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

[/code]

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:

[code language=”javascript”]

//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);
};
}

[/code]

[code language=”html”]

//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>
[/code]

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.

[code language=”javascript”]

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(”);
}));
});

[/code]

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.

4 Comentários

  • Alexandre Cardoso (@accbel)

    Post legal, Kaio. Parabéns. Angular é uma boa ferramenta. Mas aí ficou uma pergunta. Quando vc apresenta motivos para utilizar Angular em um próximo projeto, você consegue apontar projetos onde os fatores time/cultura/requisitos/negócio são mais ou menos favoráveis ao uso do Angular?

    Deixo esse link aqui (http://www.fse.guru/2-years-with-angular) para alimentar um pouco a discussão. Eu mesmo já usei Angular em algumas coisas e penso que ele se encaixa bem “nas mãos certas”.

    Abraços!

  • Kaio Valente

    Valeu Alexandre.

    Sobre a questão que levantaste, acho que a utilização do Angular se encaixa bem em times onde os papéis de desenvolvedores de front e backend são claros. A separação que o angular proporciona, até mesmo para mockar o serviços de backend, facilita um pouco o processo de desenvolvimento. Outro ponto é o que o Marcelio comentou, como tudo acaba sendo orientado a uma API Rest, fica fácil reutilizar. Contudo, nem todo mundo gosta e é adepto de JavaScript e seus callback hell, hehe, logo um time que não tenha afinidade com javascript, eu não recomendaria.

    Interessante o artigo que postaste sobre a utilização do angular. Nunca cheguei a analisar algum benchmark que analise a performance do angular em aplicações críticas. Apenas aqueles que o comparam a outros frameworks com a mesma ideologia, como backbone, ember, knockout, etc… Mas concordo quanto a utilização de style guides e padrões pra se conseguir manter uma organização mínima pensando na manutenção. Enfim, todas as tecnologias têm suas limitações e cenários onde não são adequadas.

Deixe um comentário para Marcelio Leal (@marcelioleal) Cancelar resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *