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?
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?
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;
}
arr=Array;
? –
Trichocyst new Array(3).fill(1); (3) [1, 1, 1]
–
Macarthur <ng-container *ngFor="let _ of [].constructor(20)">🐱</ng-container>
generates 🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱
_
for the variable name since i
ends up as undefined
(because the array is empty). If you actually need the index you can use *ngFor="let _ of [].constructor(20); let catNumber=index"
then Cat number {{ catNumber + 1 }} 🐱
will show you the cat number. If you have nested loops you can use _
for each and they won't conflict. –
Streusel 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;
}
arr=Array;
? –
Trichocyst new Array(3).fill(1); (3) [1, 1, 1]
–
Macarthur <div *ngFor="let dummy of ' '.repeat(20).split(''), let x = index">
Replace 20
with your variable
There are two problems with the recommended solutions using Arrays
:
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):
<table>
<thead>
<tr>
<th *ngFor="let x of colCount|times">{{ x }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let y of rowCount|times">
<th scope="row">{{ y }}</th>
<td *ngFor="let x of colCount|times">
<input type="checkbox" checked>
</td>
</tr>
</tbody>
</table>
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.
20
to a member variable.. so this will not help much –
Sprinkler *ngFor="let number of [0,1,2,3,4,5...,199,200]"
:-D –
Refrigeration 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 :
<span *appTimes="3" class="fa fa-star"></span>
this.viewContainer.clear();
before the for-loop. –
Noncontributory 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>
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;
}
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>
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>
@Input() set smpClone(loops: number) { while (--loops > 0) { this._viewContainerRef.createEmbeddedView(this._templateRef); } }
–
Impel 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.
You can use this simply:
HTML
<div *ngFor="let i of Count">
TS
export class Component implements OnInit {
Count = [];
constructor() {
this.Count.length = 10; //you can give any number
}
ngOnInit(): void {}
}
Super simple solution if you want a number from ts file so you can later on add it into the input is:
In your component.ts file:
amountOfRepetetions = new Array(20);
And in your html template (component.html) component place something like:
<ng-container *ngFor="let oneComponent of amountOfRepetetions">
<component-i-want-multiplied></component-i-want-multiplied>
</ng-container>
Note: works in Angular 15 (I didn't try it for other versions)
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<any>;
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.
<div class="content-container" *ngFor="let i of helperArray">
<general-information></general-information>
<textfields></textfields>
</div>
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:
<li *appRepeat="let i of myNumberProperty">
Index: {{i}}
</li>
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>
A variation of the top answer
@Component({
selector: 'app-loop',
template: `
<ng-template ngFor [ngForOf]="repeat(20)">🌭</ng-template>
`
})
export class LoopComponent {
protected readonly repeat = Array;
}
This displays: 🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭🌭
© 2022 - 2024 — McMap. All rights reserved.