Angular 2-NgForではなくコレクションを使う


191

...例えば...

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

次のようなことが可能です...

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

...次のような非エレガントなソリューションにアピールすることなく:

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


8
私は同じ問題を抱えています。本当に動揺して角度2でそのような単純なことを行うことはできません
。– albanx

1
多分これは参考にすることができ:stackoverflow.com/questions/3895478/...
ピチカート

回答:


197

以下のように、コンポーネント内で数値の配列(ES6)を定義できます。

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

配列の作成については、このリンクを参照してください。JavaScriptで1..20から整数の配列を作成する最も簡単な方法

次に、この配列を次のように反復できますngFor

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

またはまもなく:

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

5
うん、ティエリー!それは確かにあなたのせいではありませんが、それでも同じコンテキストです:(それはまったくエレガントではありません。しかし、あなたは非常に熟練したA2開発者なので、これ以上の解決策はないと思います。悲しいです!
Marco Jr

実際、ループ構文のAngular2にはこれは何もありません。配列を構築するには、JavaScriptが提供するものを活用する必要があります。例:Array(5).fill(4)作成する[4,4,4,4,4]
ティエリーテンプリエ2016

3
PS:@Viewアノテーションは、angular2ベータ10以降で削除されました。
Pardeep Jain

23
使用Array.fill()角度2活字にすると、次のエラー生成Supplied parameters do not match any signature of call t arget.Array.prototype.fillのドキュメントをチェック、それは...それは1つの引数が必要と言う- developer.mozilla.org/en/docs/Web/JavaScript/Reference/...
ジョシュア・ラッセル

5
Array(5).fill(1).map((x, i) => i + 1); /*[1,2,3,4,5]*/これにより、TSのエラーが解決されます
mshahbazm 2018年

90

@OP、あなたはあなたの「エレガントでない」ソリューションにひどく近かったです。

どうですか:

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

ここで私は取得していますArray:空の配列からコンストラクタを[].constructorするので、Arrayテンプレート構文で認められたシンボルではない、と私はやるのが面倒だArray=Arrayか、counter = Array彼の第四の例でやった@ pardeep、ジャイナ教のようなコンポーネントtypescriptですインチ そして、配列を取得するために必要ではないnewので、私はそれなしでそれを呼び出しnewていますArrayコンストラクターます。

Array(30)new Array(30)同等です。

配列は空になりますが、ループ内でifrom を使用したいだけなので、問題はありません;let i = index


12
これが最良の答えです。
kagronick 2018

このソリューションは、変更検出をトリガーします。新しい配列のせいだと思います。
Tobias81

1
@ Tobias81、詳しく説明してもらえますか?アプリが変更検出を実行するたびに、配列が再作成されるため、* ngForの内容が再描画されるということですか?それは間違いなく注目に値します。変更検出が実行されるたびに同じになるように、参照するTSに配列フィールドを実際に作成することで回避できます。しかし、それは望まれるよりも明らかにエレガントではありません。ティエリーテンプリエの選択した回答の2番目の例にも同じ変更検出の問題がありますか?<li *ngFor="let number of [0,1,2,3,4]">{{number}}</li>
jcairney

これは、この問題に対して見つかった最良の解決策です
khush

1
@ Tobias81では、ngForディレクティブの例の子として作成するコンポーネントのコンストラクター内にprintステートメントを配置することにより、変更検出がngForの内容を繰り返し再作成しないことを確認しました。変更検出の繰り返しごとにコンポーネントが再作成されることはないので、実際には問題があるとは思いません(少なくともAngular 8では)。
jcairney

83

コレクションではなく数値を使用するNgForのメソッドはまだありません。現時点では、* ngForはコレクションをパラメーターとしてのみ受け入れますが、次の方法でこれを行うことができます。

パイプを使用

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>

HTML(View)で数値配列を直接使用する

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

Splitメソッドの使用

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

コンポーネントでの新しい配列の作成の使用

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

作業デモ


4
Thierrysの回答に示されているようなArray.fill()方法の代わりに、配列を生成するメソッドを使用することもできres.push()ます。
ギュンターZöchbauer

はい、できますが、何か問題がありpushますか?私は両方の方法が正しいことを意味しますが、それでも違いがあれば それらの間の。
Pardeep Jain

3
いいえ、それでも素晴らしいソリューション+1。私はArray.fill()プッシュを使用したループよりもエレガントで、おそらくもっと効率的です。
ギュンターZöchbauer

1
私はこのソリューションをcounter = Arrayとてもスマートに気に入っています;)
Verri

11

コンポーネントの単純な繰り返しに配列を割り当てるという考えには耐えられなかったので、構造ディレクティブを記述しました。最も単純な形式では、テンプレートでインデックスを使用できません。次のようになります。

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


配列のアプローチは醜いことに同意しますが、これは時期尚早の最適化のように思えます。
Aluan Haddad 2017

3
もちろん、それだけでなく、ディレクティブを作成するための演習も行います。一方、それはパイプよりも長くはありません。
pdudits 2017年

これは良い点です。カスタム構造ディレクティブの概念を理解する機会は多くありません。
Aluan Haddad 2017

ナイスワン@pdudits-最新バージョンでも動作します:plnkr.co/edit/8wJtkpzre3cBNokHcDL7?p=preview [お気軽にplnkrを更新]
AT

5

Angular 5.2.6と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);
}

次のようなコンポーネントで使用できます。

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

簡潔にするために、意図的にエラーチェックとアサーションを省略しました(たとえば、ステップが負の場合にどうなるか)。


2
以下のように、HTML内の任意の方法がありますされている<div *ngfor="let i of 4, i++"></div>かもしれ
Nithila Shanmugananthanは

5

そのように使うこともできます

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

あなたは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);
}

コードはテストしていませんが、動作するはずです。


以下のように、HTML内の任意の方法がありますされている<div *ngfor="let i of 4, i++"></div>かもしれ
Nithila Shanmugananthanは

iコードで必要な場合、またはコードでインデックスを作成する場合は、次のようにできます*ngFor="let i of range; let i = index"
Alex Po

3

これは次のようにして達成することもできます:

HTML:

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

タイプスクリプト:

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

作業デモ


2

引数なしのfill()メソッド(受け入れられた回答で説明)はエラーをスローするため、次のようなものを提案します(私にとっては、Angular 7.0.4、Typescript 3.1.6で機能します)。

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

コンポーネントコード:

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

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

これは、myCollectionで何度も繰り返す、素晴らしくて迅速な方法です。

したがって、myCollectionが5の場合、Hello Worldは5回繰り返されます。


1

インデックスでカスタム構造ディレクティブを使用する:

Angularのドキュメントによると:

createEmbeddedView 埋め込みビューをインスタンス化し、このコンテナに挿入します。

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.

angularがcreateEmbeddedViewを呼び出してテンプレートを作成する場合、内部で使用されるコンテキストを渡すこともできますng-template

コンテキストオプションパラメーターを使用して、コンポーネントで使用し、* 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>

for.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

ボタンをクリックした後に配列のサイズを動的に増やしたい場合は、添付の動的ソリューションを見つけてください(これが私がこの質問にたどり着いた方法です)。

必要な変数の割り当て:

  array = [1];
  arraySize: number;

配列に要素を追加する関数を宣言します。

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

HTMLで関数を呼び出す

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

ngForを使用して配列を反復処理します。

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

以下のように、HTML内の任意の方法がありますされている<div *ngfor="let i of 4, i++"></div>かもしれ
Nithila Shanmugananthanは

配列を反復処理する必要があります。あなたがスカラーが必要な場合は、適切なサイズの配列を反復処理し、加えて、スカラーのインスタンスを作成することができます:* ngFor =「配列の項目を聞かせて、私はインデックス=ましょう」
ジャンクレメンスStoffregenを

0

私が試した最も簡単な方法

コンポーネントファイルに配列を作成することもできます。配列として返すことにより、* ngForディレクティブを使用してそれを呼び出すことができます。

このようなもの ....

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

}

そして、この関数はあなたのhtmlテンプレートファイルで使用できます

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

2
htmlには何らかの方法が<div *ngfor="let i of 4, i++"></div>あるのでしょうか
Nithila Shanmugananthan

0

私の解決策:

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

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>

これにより、取得ごとに新しい配列が作成されます。オーバーヘッドが発生する可能性がある
Remco Vlierman
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.