Angular 2 - NgFor using numbers instead collections


Translate

...for example...

<div class="month" *ngFor="#item of myCollection; #i = index">
...
</div>

Is possible to do something like...

<div class="month" *ngFor="#item of 10; #i = index">
...
</div>

...without appeal to a non elegant solution like:

<div class="month" *ngFor="#item of ['dummy','dummy','dummy','dummy','dummy',
'dummy','dummy','dummy']; #i = index">
...
</div>

?


All Answers
  • Translate

    Within your component, you can define an array of number (ES6) as described below:

    export class SampleComponent {
      constructor() {
        this.numbers = Array(5).fill().map((x,i)=>i); // [0,1,2,3,4]
        this.numbers = Array(5).fill(4); // [4,4,4,4,4]
      }
    }
    

    See this link for the array creation: Tersest way to create an array of integers from 1..20 in JavaScript.

    You can then iterate over this array with ngFor:

    @Component({
      template: `
        <ul>
          <li *ngFor="let number of numbers">{{number}}</li>
        </ul>
      `
    })
    export class SampleComponent {
      (...)
    }
    

    Or shortly:

    @Component({
      template: `
        <ul>
          <li *ngFor="let number of [0,1,2,3,4]">{{number}}</li>
        </ul>
      `
    })
    export class SampleComponent {
      (...)
    }
    

  • Translate

    No there is no method yet for NgFor using numbers instead collections, At the moment, *ngFor only accepts a collection as a parameter, but you could do this by following methods:

    Using pipe

    pipe.ts

    import {Pipe, PipeTransform} from 'angular2/core';
    
    @Pipe({name: 'demoNumber'})
    export class DemoNumber implements PipeTransform {
      transform(value, args:string[]) : any {
        let res = [];
        for (let i = 0; i < value; i++) {
            res.push(i);
          }
          return res;
      }
    }
    
    
    <ul>
      <li>Method First Using PIPE</li>
      <li *ngFor='let key of 5 | demoNumber'>
        {{key}}
      </li>
    </ul>
    

    Using number array directly in HTML(View)

    <ul>
      <li>Method Second</li>
      <li *ngFor='let key of  [1,2]'>
        {{key}}
      </li>
    </ul>
    

    Using Split method

    <ul>
      <li>Method Third</li>
      <li *ngFor='let loop2 of "0123".split("")'>{{loop2}}</li>
    </ul>
    

    Using creating New array in component

    <ul>
      <li>Method Fourth</li>
      <li *ngFor='let loop3 of counter(5) ;let i= index'>{{i}}</li>
    </ul>
    
    export class AppComponent {
      demoNumber = 5 ;
    
      counter = Array;
    
      numberReturn(length){
        return new Array(length);
      }
    }
    

    Working demo


  • Translate

    @OP, you were awfully close with your "non-elegant" solution.

    How about:

    <div class="month" *ngFor="let item of [].constructor(10); let i = index"> ... </div>

    Here I'm getting the Array constructor from an empty array: [].constructor, because Array isn't a recognized symbol in the template syntax, and I'm too lazy to do Array=Array or counter = Array in the component typescript like @pardeep-jain did in his 4th example. And I'm calling it without new because new isn't necessary for getting an array out the Array constructor.

    Array(30) and new Array(30) are equivalent.

    The array will be empty, but that doesn't matter because you really just want to use i from ;let i = index in your loop.


  • Translate

    I couldn't bear the idea of allocating an array for plain repeat of components, so I've written a structural directive. In simplest form, that doesn't make the index available to the template, it looks like this:

    import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
    
    @Directive({ selector: '[biRepeat]' })
    export class RepeatDirective {
    
      constructor( private templateRef: TemplateRef<any>,
                 private viewContainer: ViewContainerRef) { }
    
      @Input('biRepeat') set count(c:number) {
        this.viewContainer.clear();
        for(var i=0;i<c;i++) {
          this.viewContainer.createEmbeddedView(this.templateRef);
        }
      }
    }
    

    http://plnkr.co/edit/bzoNuL7w5Ub0H5MdYyFR?p=preview


  • Translate

    I solved it like this using Angular 5.2.6 and TypeScript 2.6.2:

    class Range implements Iterable<number> {
        constructor(
            public readonly low: number,
            public readonly high: number,
            public readonly step: number = 1
        ) {
        }
    
        *[Symbol.iterator]() {
            for (let x = this.low; x <= this.high; x += this.step) {
                yield x;
            }
        }
    }
    
    function range(low: number, high: number) {
        return new Range(low, high);
    }
    

    It can be used in a Component like this:

    @Component({
        template: `<div *ngFor="let i of r">{{ i }}</div>`
    })
    class RangeTestComponent {
        public r = range(10, 20);
    }
    

    Error checking and assertions omitted on purpose for brevity (e.g. what happens if step is negative).


  • Translate

    You can use lodash:

    @Component({
      selector: 'board',
      template: `
    <div *ngFor="let i of range">
    {{i}}
    </div>
    `,
      styleUrls: ['./board.component.css']
    })
    export class AppComponent implements OnInit {
      range = _.range(8);
    }
    

    I didn't test code but it should work.


  • Translate

    you can also use like that

    export class SampleComponent {
       numbers:Array<any> = [];
       constructor() {
          this.numbers = Array.from({length:10},(v,k)=>k+1);
       }
    }
    

    HTML

    <p *ngFor="let i of numbers">
       {{i}}
    </p>
    

  • Translate

    Since the fill() method (mentioned in the accepted answer) without arguments throw an error, I would suggest something like this (works for me, Angular 7.0.4, Typescript 3.1.6)

    <div class="month" *ngFor="let item of items">
    ...
    </div>
    

    In component code:

    this.items = Array.from({length: 10}, (v, k) => k + 1);
    

  • Translate

    Please find attached my dynamic solution if you want to increase the size of an array dynamically after clicking on a button (This is how I got to this question).

    Allocation of necessary variables:

      array = [1];
      arraySize: number;
    

    Declare the function that adds an element to the array:

    increaseArrayElement() {
       this.arraySize = this.array[this.array.length - 1 ];
       this.arraySize += 1;
       this.array.push(this.arraySize);
       console.log(this.arraySize);
    }
    

    Invoke the function in html

      <button md-button (click)="increaseArrayElement()" >
          Add element to array
      </button>
    

    Iterate through array with ngFor:

    <div *ngFor="let i of array" >
      iterateThroughArray: {{ i }}
    </div>
    

  • Translate

    A simplest way that i have tried

    You can also create an array in your component file and you can call it with *ngFor directive by returning as an array .

    Something like this ....

    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-morning',
      templateUrl: './morning.component.html',
      styleUrls: ['./morning.component.css']
    })
    export class MorningComponent implements OnInit {
    
      arr = [];
      i: number = 0;
      arra() {
        for (this.i = 0; this.i < 20; this.i++) {
          this.arr[this.i]=this.i;
        }
        return this.arr;
      }
    
      constructor() { }
    
      ngOnInit() {
      }
    
    }
    

    And this function can be used in your html template file

    <p *ngFor="let a of arra(); let i= index">
    value:{{a}} position:{{i}}
    </p>
    

  • Translate

    My solution:

    export class DashboardManagementComponent implements OnInit {
      _cols = 5;
      _rows = 10;
      constructor() { }
    
      ngOnInit() {
      }
    
      get cols() {
        return Array(this._cols).fill(null).map((el, index) => index);
      }
      get rows() {
        return Array(this._rows).fill(null).map((el, index) => index);
      }
    

    In html:

    <div class="charts-setup">
      <div class="col" *ngFor="let col of cols; let colIdx = index">
        <div class="row" *ngFor="let row of rows; let rowIdx = index">
          Col: {{colIdx}}, row: {{rowIdx}}
        </div>
      </div>
    </div>
    

  • Translate

    This can also be achieved like this:

    HTML:

    <div *ngFor="let item of fakeArray(10)">
         ...
    </div>
    

    Typescript:

    fakeArray(length: number): Array<any> {
      if (length >= 0) {
        return new Array(length);
      }
    }
    

    Working Demo