This is the third post in the “Working with data in Angular” series. The first post can be found here, and the second one here.

You can find the completed example app for this article on Stackblitz.

We start our commits with the initial starter Angular 8 app as can be found when you first start Stackblitz.

Preparing our app

A looping staircase Photo by Tine Ivanič, @tine999 on Unsplash

Just like in the second series in this post, we’ve gotten rid of the hello component from our app.

In the same second commit of this project, we’ve updated the frontends array of data like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  frontends = [
    {
      name: 'Angular',
      details: [
        { type: 'framework' },
        { currentVersion: 8 }
      ]
    },
    {
      name: 'React',
      details: [
        { type: 'library' },
        { currentVersion: 16.9 }
      ]
    }
  ];
}

In the previous post in this series, we had an array that contained some objects. These objects, in turn, had some properties and some nested objects.

In this example, we also have an array, and this array also has nested objects. Inside these objects, we have some properties, and some nested arrays.

Furthermore, these nested arrays contain a couple of nested objects inside, with just a single key-value pair.

This is a rather unusual structure of data, and it’s sort of difficult to loop over it in your component’s HTML template file.

If you tried just a regular *ngIf directive, you’d be left with an incomplete table.

Let’s first look at the solution, and then we’ll explain it.

Looping over a nested array of objects in a component’s HTML template

The commit at this point is available here.

This is what our HTML template, the app.component.html file looks like after the update:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<h1>Frontends:</h1>
<table>
  <tr>
    <th>#</th>
    <th>Name</th>
    <th>Type</th>
    <th>Current Version</th>
  </tr>
  <tr *ngFor="let f of frontends; let i = index ">
    <td>{{ i + 1 }}</td>
    <td>{{ f.name }}</td>
    <ng-container *ngFor="let d of f.details;">
      <td *ngIf="d.type">{{ d.type }}</td>
      <td *ngIf="d.currentVersion">{{ d.currentVersion }}</td>
    </ng-container>
  </tr>
</table>

If we previewed the app at this point, we’d see that everything works: Successfully displaying nested arrays of objects in an Angular 8 template file

On line 9 of the above code, we see the *ngFor directive that’s set up to loop over the data in the frontends array:

<tr *ngFor="let f of frontends; let i = index ">
    <td>{{ i + 1 }}</td>
    <td>{{ f.name }}</td>

If you’ve read the second post in this series, the code above should be familiar.

Then, on line 12, we see this strange code:

<ng-container *ngFor="let d of f.details;">
    <td *ngIf="d.type">{{ d.type }}</td>
    <td *ngIf="d.currentVersion">{{ d.currentVersion }}</td>
</ng-container>

Let’s break it down.

Using ng-container

We need to add another *ngFor directive to our table’s <td> tags. But we can’t add it to the tags themselves, because that would duplicate the <td> tags twice.

If only we could somehow add an *ngFor without repeating the <td> tag, that would be awesome!

Actually, that’s exactly what we’re doing here with the custom <ng-container> tag. It repeats the code inside, without us having to repeat the parent too.

Next, we need to display a <td> if our frontend’s details array has an object whose key is type. We perform the exact same logic to check for d.currentVersion.

Using these couple of tricks, we’ve successfully populated our table and extracted the date form our funnily-shaped frontends array, in only a few simple lines of code!

We’ve just learned how easy it is to loop over nested arrays of objects in Angular. We’ll soon be adding part 4 in this series.