Angular2+ ngFor 2D Arrays to Create Powerful Bootstrap Grids

Nicholas Hrboka
3 min readAug 25, 2020

The Goal

I want to create a grid of images using bootstrap within Angular. These images will not be hard coded, and I want the flexibility of choosing, for example, between 8 images or 16 images. The only rule I will follow on my CMS is that the total will always be divisible by 4. As in 4 images per row.

The Problem

As with all ideas, you run into issues upon execution. My first thought was to store them in an array with the typescript file. Once stored, I would use *ngFor to loop through, and use a conditional to check the index. If the index is 4, then I simply created a div with the class row, like so.

div *ngFor="let t of talent; let i = index"> 
<div class="row" *ngIf="i + 1 == 1">
<div class="row" *ngIf="i + 1 % 4 == 0">

<div class="col-sm-3">
<h2>{{t}}</h2>
</div>
</div>

Notice the problem? No closing tags on the new divs! Turns out, you can’t use an angular conditional in an closing tag. Ignoring my slightly flawed conditional logic, this seems to be a dead end. After some brainstorming, I looked away form the HTML, and focused my attention on how I was storing the data instead.

talent = [];for(let i =0; ......

The Solution

Using my test data, I filled an array with the file locations using a simple for loop. It is here where the solution lies. I thought in terms of pagination, how I could loop though four images and then paginate the next four. That train of thought led to the ultimate solution: a two dimensional array. The process I envisioned is as follows.

  1. Change talent to a two dimensional array.
  2. Within the for loop that populates my talent array, write a conditional that checks if the index is after every fourth image, then push a new array within talent.
  3. Using a counter to count how many 2nd dimension arrays, I push the new data into the latest dimensional array.

See the typescript solution below:

talent = [[]];ngOnInit(): void {
let j = 0;
for(let i = 0; i < 16; i++) {
if(i !== 0 && i % 4 == 0) {
this.talent.push([]);
j++;
}
this.talent[j].push(`/assets/images/people/${i + 1}.jpg`);
}
}

Now we focus to the HTML.

  1. Use *ngFor on the talent array for the div with the class of row.
  2. Use a nested *ngFor with the inner array with the class col-sm-3.
  3. Test the data!
<div *ngFor="let group of talent" class="row"> 
<div *ngFor="let person of group" class="col-sm-3">
<img [src]="person">
</div>
</div>

https://gfycat.com/educatedblondgroundbeetle

Of course, the final product needs some styling, but as you can see, it works!

If this helped you out, let me know by leaving a comment!

Cheers!

--

--