I have an int property named "count" in my component.
I would like to display a p tag X amount of times, where X is the int my count property equals. Is there really no simple way to do this, besides messing with fake arrays?
I have an int property named "count" in my component.
I would like to display a p tag X amount of times, where X is the int my count property equals. Is there really no simple way to do this, besides messing with fake arrays?
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.
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;
}
}
<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 :)
I solved it using :
In TS:
months = [...Array(12).keys()];
In Template:
<p *ngFor="let month of months">{{month+1}}</p>
According Angular documentation:
createEmbeddedView()
Instantiates an embedded view and inserts it into this container. it accepts a context object as second parameter:abstract createEmbeddedView(templateRef: TemplateRef, context?: C, index?: number): EmbeddedViewRef
.
When angular creates template by calling createEmbeddedView it can also pass context that will be used inside ng-template
.
Using context optional parameter, you may use it in the component extracting it within the template just as you would with the *ngFor.
app.component.html:
<p *for="randomNumber; let i = index; let first = first; let last = last; let even = even, let odd = odd; length = length">
index :{{i}},
length:{{length}},
is first : {{first}},
is last : {{last}},
is even : {{even}},
is odd : {{odd}}
</p>
for.directive.ts:
import { Directive, Input, TemplateRef, ViewContainerRef, EventEmitter } from '@angular/core';
@Directive({
selector: '[for]'
})
export class ForDirective {
constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) { }
@Input('for') set loop(num: number) {
for (var i = 0; i < num; i++)
this.viewContainer.createEmbeddedView(
this.templateRef,
{
index: i,
odd: i % 2 == 1,
even: i % 2 == 0,
first: i == 0,
last: i == num,
length: num - 1,
}
);
}
}