Repeat HTML element multiple times using ngFor based on a number

Angular

Angular Problem Overview


How do I use *ngFor to repeat a HTML element multiple times?

For eg: If I have a member variable assigned to 20. How do I use the *ngFor directive to make a div repeat 20 times?

Angular Solutions


Solution 1 - Angular

<ng-container *ngFor="let _ of [].constructor(20)">🐱</ng-container>

generates 

Solution 2 - Angular

You could use the following:

@Component({
  (...)
  template: `
    <div *ngFor="let i of Arr(num).fill(1)"></div>
  `
})
export class SomeComponent {
  Arr = Array; //Array type captured in a variable
  num:number = 20;
}

Or implement a custom pipe:

import {PipeTransform, Pipe} from '@angular/core';

@Pipe({
  name: 'fill'
})
export class FillPipe implements PipeTransform {
  transform(value) {
    return (new Array(value)).fill(1);
  }
}

@Component({
  (...)
  template: `
    <div *ngFor="let i of num | fill"></div>
  `,
  pipes: [ FillPipe ]
})
export class SomeComponent {
  arr:Array;
  num:number = 20;
}

Solution 3 - Angular

<div *ngFor="let dummy of ' '.repeat(20).split(''), let x = index">

Replace 20 with your variable

Solution 4 - Angular

There are two problems with the recommended solutions using Arrays:

  1. It's wasteful. In particular for large numbers.
  2. You have to define them somewhere which results in a lot of clutter for such a simple and common operation.

It seems more efficient to define a Pipe (once), returning an Iterable:

import {PipeTransform, Pipe} from '@angular/core';

@Pipe({name: 'times'})
export class TimesPipe implements PipeTransform {
  transform(value: number): any {
    const iterable = <Iterable<any>> {};
    iterable[Symbol.iterator] = function* () {
      let n = 0;
      while (n < value) {
        yield ++n;
      }
    };
    return iterable;
  }
}

Usage example (rendering a grid with dynamic width / height):

{{ x }}
{{ y }}

Solution 5 - Angular

You can simple do this in your HTML:

*ngFor="let number of [0,1,2,3,4,5...,18,19]"

And use the variable "number" to index.

Solution 6 - Angular

A simpler and a reusable solution maybe to use custom structural directive like this.

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appTimes]'
})
export class AppTimesDirective {

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef) { }

  @Input() set appTimes(times: number) {
    for (let i = 0 ; i < times ; i++) {
      this.viewContainer.createEmbeddedView(this.templateRef);
    }
  }

}

And use it like this :

Solution 7 - Angular

The most efficient and concise way to achieve this is by adding an iterator utility. Don't bother yielding values. Don't bother setting a variable in the ngFor directive:

function times(max: number) { return { [Symbol.iterator]: function* () { for (let i = 0; i < max; i++, yield) { } } }; }

@Component({
  template: ```
<ng-template ngFor [ngForOf]="times(6)">
  repeats 6 times!
</ng-template>

```
})
export class MyComponent {
  times = times;
}

Solution 8 - Angular

Best and simple way of doing nth time repetition is [].constructor(nth)

Example for 5 times loop

 <ng-container *ngFor="let _ of [].constructor(5); let i = index">
    <b>{{ i }}</b>
 </ng-container>

Solution 9 - Angular

You don't need to fill the array like suggested in most answers. If you use index in your ngFor loop all you need to create is an empty array with the correct length:

const elements = Array(n); // n = 20 in your case

and in your view:

<li *ngFor="let element in elements; let i = index">
  <span>{{ i }}</span>
</li>

Solution 10 - Angular

I know you specifically asked to do it using *ngFor, but i wanted to share the way i solved this using an structural directive:

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({ selector: '[appRepeat]' })
export class RepeatDirective {
  constructor(private templateRef: TemplateRef<any>, private viewContainerRef: ViewContainerRef) {
  }

  @Input() set appRepeat(loops: number) {
    for (let index = 0; index < loops; ++index) {
      this.viewContainerRef.createEmbeddedView(this.templateRef);
    }
  }
}

With that you can use it just like this:

<div *appRepeat="15">
  Testing
</div>

Solution 11 - Angular

You can use this simply:

HTML

TS

export class Component implements OnInit { Count = [];

  constructor() {
    this.Count.length = 10; //you can give any number
  }

  ngOnInit(): void {}
}

Solution 12 - Angular

If you are using Lodash, you can do the following:

Import Lodash into your component.

import * as _ from "lodash";

Declare a member variable within the component to reference Lodash.

lodash = _;

Then in your view, you can use the range function. 20 can be replaced by any variable in your component.

*ngFor="let number of lodash.range(20)"

It must be said that binding to functions in the view might be costly, depending on the complexity of the function you are calling as Change Detection will call the function repeatedly.

Solution 13 - Angular

Simpler approach:

Define a helperArray and instantiate it dynamically (or static if you want) with the length of the count that you want to create your HTML elements. For example, I want to get some data from server and create elements with the length of the array that is returned.

export class AppComponent { helperArray: Array;

  constructor(private ss: StatusService) {
  }

  ngOnInit(): void {
    this.ss.getStatusData().subscribe((status: Status[]) => {
      this.helperArray = new Array(status.length);
    });
  }
}

Then use the helperArray in my HTML template.

Solution 14 - Angular

Here's a slightly improved version of Ilyass Lamrani's structural directive that allows you to use the index in your template:

@Directive({ selector: '[appRepeatOf]' }) export class RepeatDirective {

  constructor(private templateRef: TemplateRef<any>,
              private viewContainer: ViewContainerRef) {
  }

  @Input()
  set appRepeatOf(times: number) {
    const initialLength = this.viewContainer.length;
    const diff = times - initialLength;

    if (diff > 0) {
      for (let i = initialLength; i < initialLength + diff; i++) {
        this.viewContainer.createEmbeddedView(this.templateRef, {
          $implicit: i
        });
      }
    } else {
      for (let i = initialLength - 1; i >= initialLength + diff ; i--) {
      this.viewContainer.remove(i);
    }
  }

}

Usage:

  • Index: {{i}}
  • Solution 15 - Angular

    You can do this :

    Ts:

       CreateTempArray(number){
       var arr=[];
       for(let i=0;i<number;i++){
         arr[i]="";
       }
       return arr;
      }
    

    Html:

    <div *ngFor="let i of CreateTempArray(20);">
        cycle 20 times
    </div>
    

    Attributions

    All content for this solution is sourced from the original question on Stackoverflow.

    The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

    Content TypeOriginal AuthorOriginal Content on Stackoverflow
    QuestiontakeradiView Question on Stackoverflow
    Solution 1 - AngularttulkaView Answer on Stackoverflow
    Solution 2 - AngularThierry TemplierView Answer on Stackoverflow
    Solution 3 - AngularAximiliView Answer on Stackoverflow
    Solution 4 - AngularAndreas BaumgartView Answer on Stackoverflow
    Solution 5 - AngularDekonunesView Answer on Stackoverflow
    Solution 6 - AngularIlyass LamraniView Answer on Stackoverflow
    Solution 7 - AngularAmit PortnoyView Answer on Stackoverflow
    Solution 8 - Angularuser8462556View Answer on Stackoverflow
    Solution 9 - AngularWiltView Answer on Stackoverflow
    Solution 10 - AngularJavier CampónView Answer on Stackoverflow
    Solution 11 - AngularJanitha RasangaView Answer on Stackoverflow
    Solution 12 - AngularDavyView Answer on Stackoverflow
    Solution 13 - AngularFlorian LeitgebView Answer on Stackoverflow
    Solution 14 - AngularMK10View Answer on Stackoverflow
    Solution 15 - AngularMohammad YaghobnezhadView Answer on Stackoverflow