Sudut 2 - NgFor menggunakan angka sebagai pengganti koleksi


191

...sebagai contoh...

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

Apakah mungkin untuk melakukan sesuatu seperti ...

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

... tanpa menarik solusi yang tidak elegan seperti:

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

?


8
Saya memiliki masalah yang sama. Benar-benar kesal orang tidak bisa melakukan hal-hal sederhana dengan sudut 2.
albanx

1
Mungkin ini bisa membantu: stackoverflow.com/questions/3895478/…
Pizzicato

Jawaban:


198

Di dalam komponen Anda, Anda dapat menentukan array angka (ES6) seperti yang dijelaskan di bawah ini:

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]
  }
}

Lihat tautan ini untuk pembuatan array: Cara tersest untuk membuat array bilangan bulat dari 1..20 di JavaScript .

Anda kemudian dapat mengulangi array ini dengan ngFor:

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

Atau sebentar lagi:

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

5
Ya, Thierry! Ini bukan kesalahan Anda, memang, tetapi masih pada konteks yang sama :( Ini tidak elegan sama sekali. Tapi karena Anda adalah pengembang A2 yang sangat terampil, saya dapat berasumsi bahwa tidak ada solusi yang lebih baik. Menyedihkan!
Marco Jr

Faktanya, tidak ada untuk ini dalam Angular2 dalam sintaks loop. Anda perlu memanfaatkan apa yang disediakan JavaScript untuk membangun array. Misalnya: Array(5).fill(4)membuat[4,4,4,4,4]
Thierry Templier

3
PS: @Lihat anotasi telah dihapus dalam angular2 beta 10 ke atas.
Pardeep Jain

23
Menggunakan Array.fill()dalam Angular 2 Typescript menghasilkan kesalahan berikut Supplied parameters do not match any signature of call t arget.- Memeriksa dokumen Array.prototype.fill, dikatakan memerlukan 1 argumen ... developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Joshua Russell

5
Array(5).fill(1).map((x, i) => i + 1); /*[1,2,3,4,5]*/ini menyelesaikan kesalahan dalam TS
mshahbazm

90

@OP, Anda sudah sangat dekat dengan solusi "tidak elegan" Anda.

Bagaimana tentang:

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

Di sini saya mendapatkan Arraykonstruktor dari array kosong:, [].constructorkarena Arraybukan simbol yang dikenali dalam sintaks templat, dan saya terlalu malas untuk melakukan Array=Arrayatau counter = Arraydalam skrip komponen seperti @ pardeep-jain dalam contoh ke-4. Dan saya menyebutnya tanpa newkarenanew tidak perlu mengeluarkan array dari Arraykonstruktor.

Array(30) dan new Array(30) setara.

Array akan kosong, tetapi itu tidak masalah karena Anda benar-benar hanya ingin menggunakan idari ;let i = indexdalam loop Anda.


13
Ini jawaban terbaik.
kagronick

Solusi ini memicu deteksi perubahan. Saya kira karena Array baru.
Tobias81

1
@ Tobias81, bisakah kamu menjelaskan? Apakah Anda mengatakan bahwa setiap kali aplikasi menjalankan deteksi perubahan, konten * ngFor digambar ulang karena array dibuat ulang? Itu pasti perlu diperhatikan. Orang bisa mengatasinya dengan benar-benar membuat bidang array di TS untuk referensi sehingga sama setiap kali deteksi perubahan berjalan. Tapi itu pasti kurang elegan dari yang diinginkan. Apakah masalah pendeteksian perubahan yang sama ada pada contoh kedua di jawaban pilihan Thierry Templier? <li *ngFor="let number of [0,1,2,3,4]">{{number}}</li>
jcairney

ini solusi terbaik yang ditemukan untuk masalah ini
khush

1
@ Tobias81, saya telah memeriksa untuk memastikan bahwa deteksi perubahan tidak membuat ulang konten ngFor berulang kali, dengan meletakkan pernyataan cetak di dalam konstruktor komponen yang saya buat sebagai anak contoh ngFor directive. Saya tidak melihat komponen yang diciptakan ulang pada setiap iterasi Change Detection, jadi saya tidak berpikir sebenarnya ada masalah (setidaknya dalam Angular 8).
jcairney

83

Belum ada metode untuk NgFor menggunakan angka sebagai pengganti koleksi, Saat ini, * ngFor hanya menerima koleksi sebagai parameter, tetapi Anda bisa melakukan ini dengan metode berikut:

Menggunakan pipa

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>

Menggunakan array angka secara langsung dalam HTML (Lihat)

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

Menggunakan metode Split

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

Menggunakan pembuatan array New di komponen

<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);
  }
}

Demo kerja


4
Anda juga bisa menggunakan Array.fill()metode untuk menghasilkan array bukan res.push()seperti yang ditunjukkan pada jawaban Thierrys.
Günter Zöchbauer

ya saya bisa tetapi apakah ada yang salah dengan push? maksud saya kedua metode sudah benar tetapi masih jika ada perbedaan. diantara mereka.
Pardeep Jain

3
Tidak, masih solusi bagus +1. Saya hanya menemukan yang Array.fill()lebih elegan daripada loop menggunakan push dan juga mungkin lebih efisien.
Günter Zöchbauer

1
Saya suka solusi ini dengan counter = Array, sangat cerdas;)
Verri

11

Saya tidak tahan dengan ide mengalokasikan array untuk pengulangan komponen, jadi saya telah menulis arahan struktural. Dalam bentuk paling sederhana, itu tidak membuat indeks tersedia untuk templat, sepertinya ini:

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


Saya setuju pendekatan array jelek, tetapi ini sepertinya optimasi prematur bagi saya.
Aluan Haddad

3
Tentu saja, tetapi juga latihan menulis arahan. Di sisi lain itu tidak lebih dari pipa, yang akan menjadi pendekatan waras kedua.
pdudits

Itu poin yang bagus, tidak ada banyak peluang untuk mendapatkan sebagian dari Anda dengan konsep arahan struktural khusus.
Aluan Haddad

Nice one @pdudits - Masih berfungsi dengan versi terbaru: plnkr.co/edit/8wJtkpzre3cBNokHcDL7?p=preview [jangan ragu untuk memperbarui plnkr Anda]
AT

5

Saya menyelesaikannya seperti ini menggunakan Angular 5.2.6 dan 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);
}

Ini dapat digunakan dalam Komponen seperti ini:

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

Pemeriksaan kesalahan dan pernyataan yang dihilangkan dengan sengaja untuk singkatnya (mis. Apa yang terjadi jika langkah negatif).


2
Apakah ada cara html pada <div *ngfor="let i of 4, i++"></div>mungkin
Nithila Shanmugananthan

5

Anda juga bisa menggunakan seperti itu

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>

4

Anda dapat menggunakan 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);
}

Saya tidak menguji kode tetapi harus berhasil.


Apakah ada cara html pada <div *ngfor="let i of 4, i++"></div>mungkin
Nithila Shanmugananthan

Jika Anda perlu iatau mengindeks dalam kode maka Anda dapat melakukannya*ngFor="let i of range; let i = index"
Alex Po

3

Ini juga dapat dicapai seperti ini:

HTML:

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

Naskah:

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

Demo yang Bekerja


2

Karena metode fill () (disebutkan dalam jawaban yang diterima) tanpa argumen melemparkan kesalahan, saya akan menyarankan sesuatu seperti ini (berfungsi untuk saya, Angular 7.0.4, Typescript 3.1.6)

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

Dalam kode komponen:

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

1
<div *ngFor="let number of [].constructor(myCollection)">
    <div>
        Hello World
    </div>
</div>

Ini adalah cara yang bagus dan cepat untuk mengulangi jumlah kali di myCollection.

Jadi jika myCollection adalah 5, Hello World akan diulang 5 kali.


1

Menggunakan Petunjuk Struktural khusus dengan indeks:

Menurut dokumentasi Angular:

createEmbeddedView Instantiates tampilan tertanam dan memasukkannya ke dalam wadah ini.

abstract createEmbeddedView(templateRef: TemplateRef, context?: C, index?: number): EmbeddedViewRef.

Param          Type           Description
templateRef    TemplateRef    the HTML template that defines the view.
context        C              optional. Default is undefined.
index          number         the 0-based index at which to insert the new view into this container. If not specified, appends the new view as the last entry.

Saat sudut membuat templat dengan memanggil createEmbeddedView, ia juga dapat meneruskan konteks yang akan digunakan di dalamnya ng-template.

Menggunakan parameter opsional konteks, Anda dapat menggunakannya dalam komponen, mengekstraknya di dalam template seperti halnya dengan * ngFor.

app.component.html:

<p *for="number; let i=index; let c=length; let f=first; let l=last; let e=even; let o=odd">
  item : {{i}} / {{c}}
  <b>
    {{f ? "First,": ""}}
    {{l? "Last,": ""}}
    {{e? "Even." : ""}}
    {{o? "Odd." : ""}}
  </b>
</p>

untuk.directive.ts:

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

class Context {
  constructor(public index: number, public length: number) { }
  get even(): boolean { return this.index % 2 === 0; }
  get odd(): boolean { return this.index % 2 === 1; }
  get first(): boolean { return this.index === 0; }
  get last(): boolean { return this.index === this.length - 1; }
}

@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, new Context(i, num));
  }
}

0

Silakan temukan terlampir solusi dinamis saya jika Anda ingin meningkatkan ukuran array secara dinamis setelah mengklik tombol (Ini adalah bagaimana saya sampai ke pertanyaan ini).

Alokasi variabel yang diperlukan:

  array = [1];
  arraySize: number;

Deklarasikan fungsi yang menambahkan elemen ke array:

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

Aktifkan fungsi dalam html

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

Iterate through array dengan ngFor:

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

Apakah ada cara html pada <div *ngfor="let i of 4, i++"></div>mungkin
Nithila Shanmugananthan

Anda harus beralih di atas array. Jika Anda membutuhkan skalar, Anda dapat mengulangi array dengan ukuran yang tepat dan instantiate skalar sebagai tambahan: * ngFor = "biarkan item array; biarkan aku = indeks"
Jan Clemens Stoffregen

0

Cara paling sederhana yang pernah saya coba

Anda juga dapat membuat larik dalam file komponen Anda dan Anda dapat menyebutnya dengan * ngFor directive dengan mengembalikannya sebagai larik.

Sesuatu seperti ini ....

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() {
  }

}

Dan fungsi ini dapat digunakan dalam file template html Anda

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

2
Apakah ada cara html pada <div *ngfor="let i of 4, i++"></div>mungkin
Nithila Shanmugananthan

0

Solusi saya:

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);
  }

Dalam 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>

ini menciptakan Array baru di setiap get. Bisa membuat overhead
Remco Vlierman
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.