Learning Angular - Directives: ngFor
I am continuing my Learning
Angular
journey and understanding Angular’s ngFor
directive.
I will extend my current example and show more images when typing keywords into a text field.
You will understand how ngFor
works and how it can reduce code
duplication, especially in the template.
This article will take you less than four minutes to read.
Introduction
We can implement showing/hiding items based on a boolean value using
just ngIf
, a possible implementation would be:
<p *ngIf="show_ngIf">
Type 'ngIf' to Display
</p>
<img *ngIf="show_dog"
src="https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1">
For two items, this implementation is fine. When there are more than
three items, say: ngIf
, dog
, cat
, cow
, the above
implementation starts to look like:
<p *ngIf="show_ngIf">
Type 'ngIf' to display
</p>
<img *ngIf="show_dog"
src="https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1">
<img *ngIf="show_cat"
src="https://www.dropbox.com/s/ip7trvghw45n4yc/cat.jpeg?raw=1">
<img *ngIf="show_cow"
src="https://www.dropbox.com/s/h7kfnipb6ix1xxb/cow.jpeg?dl=0">
Displaying four items requires thirteen lines of code in the template. If there are more, this approach becomes unwieldily.
Following Along
If you would like to follow along with this code, you can use the Github link to get a final copy of the code or view the project in your browser using this StackBlitz link.
ngFor
to the Rescue
Angular has another structural
directive: ngFor
,
that is equivalent to a for
loop in other programming languages.
Restructure data
Before we start, instead of having: show_<item>
variable in our
component code, I will put everything into a better data structure for
the data and its intended usage.
words = {
"cat": {
"show": false,
"url": "https://www.dropbox.com/s/ip7trvghw45n4yc/cat.jpeg?raw=1",
},
"dog": {
"show": false,
"url": "https://www.dropbox.com/s/ugeqlxvawfqwhth/dog_by_roaming_angel.jpeg?raw=1",
},
"cow": {
"show": false,
"url": "https://www.dropbox.com/s/h7kfnipb6ix1xxb/cow.jpeg?raw=1",
},
"ngIf": {
"show": false,
"url": "",
}
}
Moving forward, words
or this.words
refer to the above data
structure.
Listing Words
Before attacking the problem directly, lets use just ngFor
to solve
a problem.
Listing out the words available for the text box will make this interaction more user-friendly.
<ul *ngFor="let word of word_list" >
<li>{{ word }}</li>
</ul>
The component code:
word_list = Object.keys(this.words)
This displays in the browser:
- cat
- dog
- cow
- ngIf
Using ngFor
with this new data structure, it’s easy to display all
the available options. When adding more items to the data structure,
there’s nothing to change in other parts of the code.
Syntax of ngFor
To iterate every item
in an item_list
array using ngFor
would
have syntax:
<div ngFor="let item in item_list">
{{ item }}
</div>
Here, ngFor
returns every element in item_list
as item
. Listing
out words, I used: word_list
to store all the words from the words
data structure.
ngFor
Limitation
JavaScript/Typescript has another function to get all the keys of an
object: Object.keys(words)
. Why not use that?
ngFor
in the template does not allow complex expressions, such as:
<div ngFor="let item in Object.keys(items)">
{{ item }}
</div>
Where items
is an object containing items. The way I solved this is
to have item_list
in the component that stores the items:
item_list = Object.keys(this.items)
Displaying Images with ngFor
and ngIf
As we can easily list all the words out supported, how can we display the images associated with them?
The image tag needs to use ngIf
to show when words.dog.show
is
true
. For example:
<img *ngIf="words.dog.show"
[src]="words.dog.url">
Repeating this each time would just be the same as the initial implementation.
<img *ngIf="words.ngIf.show"
[src]="words.ngIf.url">
<img *ngIf="words.dog.show"
[src]="words.dog.url">
<img *ngIf="words.cat.show"
[src]="words.cat.url">
<img *ngIf="words.cow.show"
[src]="words.cow.url">
It’s down from thirteen lines to eight lines, so there is an improvement.
Can we do better?
With ngFor
, there is a better way!
Using the word_list
and ngFor
, to display all the images where the
words[word].show
is true
, the code can be:
<div *ngFor="let word of word_list" >
<img *ngIf="words[word].show"
[src]="words[word].url">
</div>
In the twice the number of lines as showing one image, we can display
all the proper images, even when adding more entries to words
list.
Conclusion
Using ngFor
with the right data structure allows for efficient
processing of lists.
ngFor
syntax is similar to JavaScript/Type Script’s for
syntax and
available in the template for simple evaluation.