Angular.js - Montando listas ou tabelas usando loops com ng-repeat

No artigo anterior vimos como trabalhar com estilos CSS e classes além de conhecer algumas novas diretivas e como elas são uma espécie de atalho para os desenvolvedores.

Hoje vamos avançar um pouco mais e trazer um assunto bem útil, que é a criação de listas e tabelas dinamicamente, através de loops.

É comum as listas ou tabelas serem criadas do lado servidor, fazendo-se loops dos dados vindos de um banco de dados ou array mas fazer esta mesma ação do lado cliente é menos comum.

Como a ideia do Algular.js é trabalhar dados fornecidos no formato Json, devemos ter em mente que criar uma lista ou tabela pode ser feita sim do lado cliente de maneira fácil e, além disto, contribuir para a prática da programação baseada em MVC, ou seja, que separa as camadas de layout das demais.

Além disto vamos aproveitar a oportunidade e tratar também de uma outra maneira de aplicar as técnicas de estilos CSS.

O exemplo abaixo será nossa base de estudos neste artigo.

<html ng-app>
<head>
<title>Classes</title>
<style>
.selected {
background-color: lightgreen;
}
</style>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
</head>
<body>
<table ng-controller='RestaurantTableController'>
<tr ng-repeat='restaurant in directory' ng-click='selectRestaurant($index)' ng-class='{selected: $index==selectedRow}'>
<td>{{restaurant.name}}</td>
<td>{{restaurant.cuisine}}</td>
</tr>
</table>
<script>
function RestaurantTableController($scope) {
$scope.directory = [
{
name:'The Handsome Heifer',
cuisine:'BBQ'
},
{
name:'Green\'s Green Greens',
cuisine:'Salads'
},
{
name:'House of Fine Fish',
cuisine:'Seafood'
}
];

$scope.selectRestaurant = function(row) {
$scope.selectedRow = row;
};
}
</script>
</body>
</html>

Em primeiro lugar definimos o trecho do código que será controlado pelo Angular.js. Isto é feito através da diretiva ng-controllerng-controller='RestaurantTableController' informa que a função RestaurantTableController controlará tudo que vai de <table> a </table>. É dentro desta marcação de tabela que faremos nosso loop com os dados para criar uma tabela.

É dentro da variável $scope que ficam todas as propriedades e funções/métodos que precisaremos acessar a fim de montar a tabela.

Os dados a serem utilizados para a geração da tabela, por exemplo, estão dentro de $scope.directory. Note que temos duas propriedades (ou neste caso campos) dentro desta variável: 'name' e 'cuisine'. Perceba também que em nossa tabela temos as marcações <td>{{restaurant.name}}</td><td>{{restaurant.cuisine}}</td>. Por ai acredito que esteja mais claro onde os dados serão impressos.

Mas como o loop é criado e controlado?

Bem, ele é controlado por outra diretiva, a ng-repeat. Para quem já trabalhou com loops em Javascript puro vai se familiarizar rápido com a sintaxe. ng-repeat='restaurant in directory' lê a variável $scope.directory e a 'quebra' em linhas, chamadas restaurant. Assim cada linha de 'name' e 'cuisine' será atribuída a uma 'volta' de restaurant no loop. É por isso que dentro dos <td>s a variável chama-se restaurant.name ao invés de directory.name.

Agora que o loop está feito vamos a segunda parte do script, o estilo CSS.

Se você executar o script acima perceberá que cada linha clicada na tabela faz seu background destacar-se com um fundo verde. Este efeito é obtido graças a duas diretivas que já vimos no artigo anterior: ng-click e ng-class. A diferença neste caso é como capturamos a informação do clique. Neste caso o que nos interessa é saber qual linha foi clicada. Esta informação é obtida por meio de ng-click='selectRestaurant($index)' onde selectRestaurant é uma função dentro do controller RestaurantTableController que capturará o clique e $index é a variável que traz consigo o índice que nos informa em que linha do loop acabamos de clicar.

É importante notar que $index é uma palavra reservada do Angular.js, sendo assim se você tentar utilizar qualquer outro nome de variável ao invés de $index para capturar a informação de índice terá como resposta um erro. Assim $index deve ser sempre utilizado para retornar índices.

ng-class='{selected: $index==selectedRow}' controla a exibição ou não do estilo chamado selected, declarado dos estilos <style></style>

Assim como no artigo anterior o que dirá para a diretiva ng-class aplicar o estilo selected será o estado true ou falseng-class='{selected: true}' exibe o estilo e ng-class='{selected: false}' não o exibe. No caso do exemplo acima usamos um truque bem sagaz! $index nos ajudará a dizer quando ativar ou não o estilo. As linhas em que $index for igual a  selectedRow serão as marcadas. Se você olhar bem, elas serão exatamente as linhas clicadas. Mas por que?

$index em ng-class sempre carregará consigo o índice da linha atual em que está e selectedRow será atribuído com 0,1,2,... apenas nas linhas que forem clicadas. Esta atribuição é feita por meio da função $scope.selectRestaurant que atribui o valor de $scope.selectedRow ao retorno do clique que carrega consigo $index.

Antes de qualquer interação $scope.selectedRow carrega undefined consigo. Assim 0==undefined é false, 1==undefined é false e 2==undefined também é false. É por isso que ao carregar o script nenhuma linha aparece destacada em verde. Quando clicamos em uma linha fazemos $scope.selectedRow = 0, a 1 ou a 2, dependendo de qual linha clicamos.

Nos casos em que 0==0, 1==1 ou 2==2 teremos como resultado true o que faz ativar o estilo selected na exata linha clicada.

Bem, assim terminamos mais um artigo desta série dedicada ao Angular.js. Abraço!

Comentários

Postagens mais visitadas deste blog

MySQL - Completando quantidades fixas de caracteres com as funções LPAD() e RPAD()

MySQL - Clonando tabelas na linha de comando

PHP - Gerando arquivo em UTF-8 com fwrite() e utf8_encode()