Repeat HTML element multiple times using ngFor based on a number
AngularAngular 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
:
- It's wasteful. In particular for large numbers.
- 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:
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>