htmlangularangular19angular-compiler

How to add a new row every nth loop in Angular @for?


I want to create a new row every 6 iterations of a loop, but because I have a div tag in an if with no closing div, I'm getting an error.

What is the correct, "Angular 19" way to do this?

<div class='container'>
  @for(role of userRoles; track role.id){
    @if(+role.id % 6 === 0){
      <div class="row">
    }                        <<<<<< Error here <<<<<<<
    <div class="col-2">
      {{role.name}}
    </div>
    @if(+role.id % 6 === 5){
      </div>
    }
  }
</div>

The error is:

Unexpected closing block. The block may have been closed earlier. If you meant to write the } character, you should use the "}" HTML entity instead.ngtsc(-995002)


Solution

  • Angular expects every opening HTML tag element to have a closing tag element (excluding self closing tags <img src="..." />).

    So we need to split the array at the nth element and then loop through to create the row in between nth elements.

    splitAtN(userRoles: any[], n: number) {
      const output = [],
        i = 0;
      while (userRoles.length) {
        output.push(userRoles.slice(i == 0 ? 0 : i + 1, i + n));
        userRoles = userRoles.slice(i + n);
      }
      return output;
    }
    

    Full Code:

    import { Component } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    
    @Component({
      selector: 'app-root',
      template: `
        <div class='container'>
          @for(userRolesNth of userRolesTransformed; track $index){
            <div class="row">
            @for(role of userRolesNth; track role.id) {
              <div class="col-2">
                {{role.name}}
              </div>
            }
            </div>
          }
        </div>
      `,
    })
    export class App {
      userRoles = [
        { name: '1', id: 1 },
        { name: '2', id: 2 },
        { name: '3', id: 3 },
        { name: '4', id: 4 },
        { name: '5', id: 5 },
        { name: '6', id: 6 },
        { name: '7', id: 7 },
        { name: '8', id: 8 },
        { name: '9', id: 9 },
        { name: '10', id: 10 },
        { name: '11', id: 11 },
        { name: '12', id: 12 },
        { name: '13', id: 13 },
        { name: '14', id: 14 },
      ];
    
      userRolesTransformed: any[] = [];
    
      ngOnInit() {
        this.userRolesTransformed = this.splitAtN(this.userRoles, 5);
      }
    
        splitAtN(userRoles: any[], n: number) {
          const output = [],
            i = 0;
          while (userRoles.length) {
            output.push(userRoles.slice(i == 0 ? 0 : i + 1, i + n));
            userRoles = userRoles.slice(i + n);
          }
          return output;
        }
    }
    
    bootstrapApplication(App);
    

    Stackblitz Demo