Sabe quando você vê postagens em uma rede social e elas aparecem uma atrás da outra?
Isso acontece com ajuda de um poderoso loop de repetição que percorre e cria todas as postagens, uma a uma…
E se você também precisa criar múltiplos elementos na sua aplicação…
Então o ngFor
é a arma certa para ter no seu Arsenal de Programador.
Por isso continue lendo esse artigo para descobrir como tirar o melhor proveito desse recurso incrível e aprender mais sobre:
Exibir múltiplos elementos com Angular ngFor
Ngfor
é uma diretiva Angular que permite percorrer um array, ou qualquer objeto iterável, e exibir cada item do array como elemento na tela.
E o que isso deveria significar?
Colocar o ngFor
em um elemento HTML, ou componente, cria várias cópias desse elemento para cada item do array fornecido.
Alias o Angular ngFor tem o comportamento parecido com o loop for nas linguagens de programação…
Lembre que apesar de serem cópias, os elementos gerados podem variar com base nos valores do array.
Como usar o Angular ngFor?
A escrita do ngFor
é simples e bonita, basta colocar no elemento, ou componente, e informar qual array ele deve usar.
Então primeiro vamos precisar de um array:
@Component({
selector: 'app-user',
templateUrl: './user.component.html'
})
export class UserComponent {
const users = [
{id: 1, name: 'Gabriel'},
{id: 2, name: 'Pedro'},
{id: 3, name: 'Julia'}
];
}
Depois fornecemos o array users
para a diretiva ngFor
dentro de uma tag… no caso a tag li
.
Assim criamos um elemento de lista para cada valor de users
.
<ul>
<li *ngFor="let user of users"> {{ user.name }} </li>
</ul>
Primeiro observe que:
- A sintaxe
of users
significa que iremos iterar, ou percorrer, o array de usuários; - E depois
let user
cria uma variável local que disponibiliza o valor de cada usuário.
Assim você pode personalizar cada elemento com a variável user
.
Note também que você pode utilizar a variável user
em qualquer lugar dentro do ngFor
, mas nunca fora. (é parecido com um escopo de função)
Por fim veja o resultado gerado em HTML para o exemplo acima:
<ul>
<li> Gabriel </li>
<li> Pedro </li>
<li> Julia </li>
</ul>
5 variáveis para potencializar seus loops
O Angular ngFor também fornece vantagens para facilitar o seu trabalho.
Oferecendo para você algumas variáveis a cada ciclo do ngFor
.
Então coloque o seu chapéu do Indiana Jones e vamos explorar essas misteriosas variáveis!
Como obter o índice de cada item
Caso você queira numerar os itens da lista, apenas o valor do usuário não é suficiente.
Então você também precisa obter o índice de cada item.
Para isso podemos definir uma variável dentro do ngFor
e atribuir a ela o valor de index
:
<ul>
<li *ngFor="let user of users; let i = index">
{{ i }}. {{ user.name }}
</li>
</ul>
Perceba que chamamos a variável index
de “i”, mas você pode nomear como quiser.
Depois basta usar “i” dentro do ngFor
, como qualquer outra variável.
Agora veja como fica nossa saída HTML:
<ul>
<li> 0. Gabriel </li>
<li> 1. Pedro </li>
<li> 2. Julia </li>
</ul>
Além disso se você necessita exibir o tamanho total do array, o Angular dispõe outra variável chamada count
. (equivalente a users.length
)
Com o uso similar ao index
:
<ul>
<li *ngFor="let user of users; let i = index; let c = count">
{{ i }}-{{ c }}. {{ user.name }}
</li>
</ul>
Por fim o resultado do HTML gerado fica:
<ul>
<li> 0-3. Gabriel </li>
<li> 1-3. Pedro </li>
<li> 2-3. Julia </li>
</ul>
Para o nosso array de users
, o valor de count
é 3 por possuir 3 itens.
Cuidado para não confundir com o índice do último item, que corresponde ao tamanho total, menos um. (para atender a índices baseados em zero)
Como identificar o primeiro e o último item de um array
Acontece que o índice não é o único valor que podemos obter da diretiva ngFor
.
Também existem 2 outras variáveis usadas para identificar o primeiro e o último item do array.
O valor da variável é boolean, dependendo do item atual:
- first: retorna
true
se for o primeiro item do array, que corresponde ao índice 0; - last: retorna
true
se for o último item do array.
São muito úteis se você quer estilizar o primeiro ou o último item do array. Usando essas variáveis, podemos atribuir a cada uma delas uma classe CSS diferente:
<ul>
<li *ngFor="let user of users; let first = first; let last = last"
[ngClass]="{ inicio-array: first, fim-array: last }">
{{ user.name }}
</li>
</ul>
Assim adiciona uma classe CSS:
- Com nome inicio-array ao primeiro item;
- E uma com nome fim-array ao último item.
Usando even e odd para aumentar a legibilidade
Assim como first e last
, even e odd
são muito úteis para estilizar elementos.
Afinal são usados para identificar itens de índice par (como 2, 4) e itens de índice impar (como 1, 3).
Muito comum na criação de tabelas, afim de aumentar a legibilidade, ao adicionar uma classe CSS diferente às linhas pares ou ímpares.
O valor da variável também é boolean
, dependendo do item atual:
- even: retorna
true
para itens pares; - odd: retorna
true
para itens ímpares.
Então se você deseja adicionar uma classe CSS as linhas pares, use even
da seguinte maneira:
<ul>
<li *ngFor="let user of users; let even = even"
[ngClass]="{ linha-par: even }">
{{ user.name }}
</li>
</ul>
Como melhorar a performance dos seus loops
Agora que você sabe como usar o ngFor
, vamos desvendar uma parte importante do seu funcionamento.
Quando o Angular cria e destruí elementos na página, é uma operação cara em termos de desempenho. (comparando com código Javascript puro)
Normalmente a manipulação de elementos na tela ocorre quando:
- Um item é adicionado ao array;
- Um item é removido do array;
- Ou os itens do array são reordenados.
Mas não dá para você brincar de renderizar elementos…
Por isso o Angular otimiza as operações e busca reutilizar os elementos DOM existentes. Assim apenas alguns valores serão substituídos.
Por exemplo, se um item for adicionado ao array, não será renderizada a lista inteira novamente.
Em vez disso todos os elementos DOM existentes são reutilizados e apenas o elemento adicional é criado.
O mesmo acontece quando um item é removido do array ou o array é reordenando…
Mas como o Angular sabe quais elementos já existem?
Para fazer toda essa otimização, o Angular identifica cada objeto no array através de uma referência. Caso contrário, não poderá determinar “quem é quem”.
Porém o método padrão de identificação de objetos por referência é bastante limitado…
Porque se você cria um novo array com os mesmos valores do antigo e passa esse novo array para o ngFor
…
- As referências ainda serão dos objetos do array antigo;
- E não será possível identificar que os valores são semelhantes.
Então, para a identificação, o novo array contém um novo conjunto de itens, completamente diferente do anterior.
Assim o Angular desiste da otimização e renderiza a lista inteira novamente.
Essa situação é muito comum ao solicitar dados do servidor…
E como resolver esse problema?
Aumentando o desempenho do Angular ngFor com a função trackBy
A estratégia padrão de identificação do objeto não é tão ruim…
Como o Angular não possui informações sobre o objeto, então não consegue determinar qual propriedade o torna único.
Para isso você pode alterar o método padrão de identificação do Angular através da função trackBy
.
Afinal a função informa ao Angular quais propriedades do objeto são exclusivas dele.
No caso do nosso array users
, a propriedade exclusiva é o id
. Sendo que não existem 2 usuários com o mesmo id
.
Então devemos retornar o valor do id
na função trackBy
:
@Component({
selector: 'app-user',
templateUrl: './user.component.html'
})
export class UserComponent {
const users = [
{id: 1, name: 'Gabriel'},
{id: 2, name: 'Pedro'},
{id: 3, name: 'Julia'}
];
trackUser(index, user) {
return user ? user.id : null;
}
}
Note que a função recebe o índice do item e o próprio item como parâmetros.
Também precisamos informar ao ngFor
qual nova função deve usar para rastreamento:
<ul>
<li *ngFor="let user of users; trackBy : trackUser">
{{ user.name }}
</li>
</ul>
Mas quando usar o trackBy?
Em principio não é uma alteração padrão…
Como uma otimização de desempenho, é necessário apenas se você tiver problemas de desempenho.
Por exemplo, você está trabalhando com um array muito grande e a aplicação renderiza a lista do zero a cada chamada ao servidor.
Portanto impacta na velocidade de carregamento e a interface do usuário fica lenta devido à grande quantidade de elementos DOM criados e destruídos.
Parabéns por ter chegado até aqui!
Afinal esse não foi um artigo fácil…
Muitos assuntos foram abordados como:
- O que é
ngFor
e como utilizar; - Obter o índice de cada item com
index
; - Identificar o primeiro e o último item com
first e last
; - Usar
even e odd
para aumentar a legibilidade; - E aumentar a performance com a função
trackBy
.
Se você gostou, ou tem alguma dúvida, deixe seu comentário aqui abaixo:
Hey,
o que você achou deste conteúdo? Conte nos comentários.
Tenho um array e nele percorro um ngFor. Quero fazer ser possivel eu passar ele pra ele mesmo e o ngfor remontar. E possivel ? Exemplo: this.array = […this.array]
Não, não é possível. ;(
É necessário você acionar a detecção de alterações manualmente utilizando o
ChangeDetectorRef
.Dependendo do caso, a opção
trackBy
dongFor
pode ajudar.Irei deixar o link de uma questão no Stack Overflow que trata justamente disso: link aqui
Valew Gabriel, o conteúdo ajuda muito. Grande abraço para você.
Valeu, Mauro! Grande Abraço!
Muito bom, agora tenho uma duvida, se eu tiver recebendo um array vazio, ou o elemento só venha da api ou service se obtiver algum objeto dentro do array que não seja nulo, o ngFor vai dar erro pois não vai receber nada, como fazer para resolver isso, pois mesmo que tenha um ngIf ele ira dar erro pois o ngFor não ta recebendo nada, assim dando o erro [Object object] no console do navegador.
O ngFor precisa receber qualquer objeto iterável…
Nesse caso, o erro
[Object object]
normalmente acontece quando você tenta passar um objeto não iterável para o ngFor.O que é bastante comum quando você passa um valor vindo de uma API ou service, porque você recebe um objeto de resposta (não iterável).
Por exemplo, 2 situações comuns são:
1 – Passarmos o objeto de resposta inteiro e não apenas a carga útil (que seria o array com os valores, normalmente em um atributo
resposta.data
);2 – Ou recebermos um erro como resposta, sem fazer o tratamento adequado. O que faria você atribuir um valor
data
inexistente ao ngFor.Pelo seu texto, me parece ser a segunda opção…
Então a solução seria, dentro da lógica que recebe a resposta da API, acrescentar um
if
para verificar o que está chegando. (E não utilizar ongIf
para tal tratamento)OBS: É um pouco difícil ter certeza da situação sem ver o código fonte… :/
Muito bom, seus conteúdos são incríveis. Apesar de eu ser iniciante tira minhas dúvidas com clareza, muito obrigada.
Tamo junto, Mariane! o/ É muito bom ouvir isso. xD
excelente!
Massa que curtiu! xD
Muito legal tirou multas duvidas que eu tinha com relação ao ngfor. muito bom!
Top demais! Fico feliz que você saiu sem dúvidas.
Muito bom conteúdo, me ajudou, parabéns!!
Valeu, Igor!!
Segundo artigo lido hoje e parabéns novamente, conteúdo de angular em português com qualidade são poucos.
Caramba, valeu jovem! Fico contente que você achou isso! E parabéns também pela determinação na leitura. 😉
Muito bom conteudo e parabens, espero ler mais artigos obrigado
Obrigado! Fico muito feliz que tenha gostado. xD
Referências:
Angular DOC
Ultimate Courses
Malcoded
Angular University
Loiane Groner Youtube
O que eu preciso fazer é colocar uma condicional…
Algo parecido com:
<div *ngFor= "let user of users ; *ngIf: user.type=== 'local' "
Tem como?
Não, o Angular não permite o uso do
ngFor
engIf
no mesmo elemento.(Atenção: Não sei se isso irá mudar no futuro, mas no momento funciona assim.)
Você iria precisar fazer algo como:
<div *ngIf="user.type==='local'">
<div *ngFor="let user of users">
</div>
</div>