Angular 2-NgFor使用数字代替集合


190

...例如...

<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

Answers:


195

在组件内,您可以定义一个数字数组(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]
Thierry Templier

3
PS:@View注释已在angular2 beta 10及更高版本中删除。
Pardeep Jain'4

23
Array.fill()在Angular 2中使用Typescript会产生以下错误Supplied parameters do not match any signature of call t arget.-检查Array.prototype.fill文档,它说它需要1个参数... 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]*/这解决了TS中的错误
mshahbazm,

85

@OP,您的“非优雅”解决方案非常接近。

怎么样:

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

在这里,我Array从一个空数组中获取构造函数:[].constructor,因为Array在模板语法中不是公认的符号,而且我也懒得去做,Array=Array或者counter = Array像@ pardeep-jain在他的第四个示例中那样在组件打字稿中也很懒。我new之所以这么称呼它,是因为new不需要从Array构造函数中获取数组。

Array(30)new Array(30)等价。

该数组将为空,但这没关系,因为您真的只想在循环中使用ifrom ;let i = index


11
这是最好的答案。
kagronick

该解决方案触发变更检测。我猜是由于新的数组。
Tobias81 '18

1
@ Tobias81,您能详细说说吗?您是说每次应用程序运行更改检测时,都会重新绘制* ngFor的内容,因为重新创建了数组吗?绝对值得一提。可以通过在TS中实际创建一个数组字段来引用来解决该问题,因此每次运行更改检测时它都是相同的。但这绝对不会像期望的那样优雅。Thierry Templier选择的答案的第二个示例中是否存在相同的变更检测问题?<li *ngFor="let number of [0,1,2,3,4]">{{number}}</li>
jcairney

这是找到此问题的最佳解决方案
khush

1
@ Tobias81,通过将打印语句放入作为示例ngFor指令的子代创建的组件的构造函数中,我检查以确保更改检测不会反复重新创建ngFor的内容。我没有看到在每次变更检测迭代中都重新创建组件,所以我认为实际上没有问题(至少在Angular 8中)。
jcairney

83

NgFor还没有使用数字代替集合的方法,目前,* ngFor仅接受一个集合作为参数,但是您可以通过以下方法做到这一点:

使用管道

管道

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中使用数字数组(查看)

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

使用拆分方法

<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
您也可以使用Array.fill()生成数组的方法来代替res.push()Thierrys答案中所示的方法。
君特Zöchbauer

是的,我可以,但是有什么问题push吗?我的意思是两种方法都是正确的,但仍然存在差异。它们之间。
Pardeep Jain

3
不,仍然是不错的解决方案+1。我只是发现它Array.fill()比使用push的循环更优雅,而且可能也更有效。
君特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=预览


我同意数组方法很丑陋,但这对我来说似乎是过早的优化。
Aluan Haddad

3
当然,也是写指令的一种练习。另一方面,它不长于管道,这是第二种理智的方法。
pdudits

这是一个好点,使用自定义结构指令的概念的机会很少。
Aluan Haddad

尼斯一个@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 '18

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 '18

如果您需要i代码或在代码中进行索引,则可以这样做*ngFor="let i of range; let i = index"
Alex Po,


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

使用context可选参数,您可以在组件中使用它,就像使用* 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>

指令:

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 '18

您必须遍历数组。如果需要标量,则可以迭代一个具有正确大小的数组,并另外实例化一个标量:* ngFor =“让数组的项;让i = index”
Jan Clemens Stoffregen

0

我尝试过的最简单的方法

您还可以在组件文件中创建一个数组,并且可以通过返回为array来使用* 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 '18

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>

每次获取都会创建一个新的数组。可能会产生开销
雷姆科·弗利尔曼
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.