Angular4: How do I *ngFor, for every number in an int?
You could easily do it with an pipe filter which transforms an empty array to an number of childs depending on a filter param = number.
Pipe filter
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'range',
pure: false
})
export class RangePipe implements PipeTransform {
transform(items: any[], quantity: number): any {
items.length = 0;
for (let i = 0; i < quantity; i++) {
items.push(i);
}
return items;
}
}
View
<div *ngFor="let n of [] | range:100"></div>
Plnkr: https://plnkr.co/edit/Yn775KSbBeUPeyaI9sep?p=preview
You can create another variable called countObservable
countObservable = Observable.range(0, this.count).toArray();
Use async for in HTML
<p *ngFor="let num of countObservable | async" >Hello {{num}}</h2>
Update
If we need to update the number we can use flatMap
.
Instead of above code for countObservable, use this
count$= new BehaviorSubject(10);
countObservable$ =
this.count$.flatMap(count => Observable.range(0, count).toArray()) ;
To change the number value, just update count$
this.count$.next(newNum);
I kind of disliked the approach of creating an empty array of size n
every time that I wanted to render an element n
times, so I created a custom structural directive:
import { Directive, Input, TemplateRef, ViewContainerRef, isDevMode, EmbeddedViewRef } from '@angular/core';
export class ForNumberContext {
constructor(public count: number, public index: number) { }
get first(): boolean { return this.index === 0; }
get last(): boolean { return this.index === this.count - 1; }
get even(): boolean { return this.index % 2 === 0; }
get odd(): boolean { return !this.even; }
}
@Directive({
selector: '[ForNumber]'
})
export class ForNumberDirective {
@Input() set forNumberOf(n: number) {
this._forNumberOf = n;
this.generate();
}
private _forNumberOf: number;
constructor(private _template: TemplateRef<ForNumberContext>,
private _viewContainer: ViewContainerRef) { }
@Input()
set ngForTemplate(value: TemplateRef<ForNumberContext>) {
if (value) {
this._template = value;
}
}
private generate() {
for (let i = 0; i < this._forNumberOf; i++) {
this._viewContainer.createEmbeddedView(this._template, new ForNumberContext(this._forNumberOf, i));
}
}
}
And then u can use it as follows:
<ng-template ForNumber [forNumberOf]="count" let-index="index">
<span>Iteration: {{index}}!</span></ng-template>
Please note, I havent tested it extensively so I cant promise that its bulletproof :)