Angular 2 - NgFor 使用数字而不是集合

Posted

技术标签:

【中文标题】Angular 2 - NgFor 使用数字而不是集合【英文标题】:Angular 2 - NgFor using numbers instead collections 【发布时间】:2016-07-21 03:24:25 【问题描述】:

...例如...

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

?

【问题讨论】:

我也有同样的问题。真的很沮丧,不能用 angular 2 做这么简单的事情。 也许这会有所帮助:***.com/questions/3895478/… 【参考方案1】:

对于 Angular,这里有一些非常干净和简单的东西:

在 .ts 中:

max = 10;    

在 .html 中:

<div *ngFor="let dummy of ','.repeat(max).split(','); index as ix">
   - ix + 1:
</div>

【讨论】:

【参考方案2】:

我的组件.ts

numbers: number[] = [];

constructor() 
  this.numbers = new Array<number>(10)

我的组件.html

<div *ngFor="let num of numbers; let i = index"> i </div>

【讨论】:

【参考方案3】:

使用管道将数字转换为数组。

@Pipe(
  name: 'enumerate',
)
export class EnumeratePipe implements PipeTransform 
  transform(n: number): number[] 
    return [...Array(n)].map((_,i) => i);
  

然后在模板中使用管道。

<p *ngFor="let i of 5 | enumerate">
   Index:  i 
</p>

https://stackblitz.com/edit/angular-ivy-pkwvyw?file=src/app/app.component.html

【讨论】:

值在 ngFor 中不可访问 检查堆栈闪电战 我的意思是如果你需要打印 1,2,3,4,5【参考方案4】:

目前还没有 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;
  

对于较新的版本,您必须更改导入并删除 args[] 参数:

import  Pipe, PipeTransform  from '@angular/core';

@Pipe(name: 'demoNumber')
export class DemoNumber implements PipeTransform 
  transform(value) : any 
    let res = [];
    for (let i = 0; i < value; i++) 
        res.push(i);
      
      return res;
  

html:

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

使用拆分方法

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

#Working demo

【讨论】:

您也可以使用 Array.fill() 方法来生成数组,而不是像 Thierrys 回答中所示的 res.push() 是的,我可以,但push 有什么问题吗?我的意思是这两种方法都是正确的,但如果有任何差异的话。他们之间。 不,仍然是一个不错的解决方案 +1。我只是发现Array.fill() 比使用 push 的循环更优雅,而且它也可能更有效。 我喜欢counter = Array的这个解决方案,非常聪明;) 当然import Pipe, PipeTransform from '@angular/core';。编辑:好的,我知道了,将编辑您的帖子以更新版本。【参考方案5】:

使用带有索引的自定义结构指令:

根据 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));
  

【讨论】:

【参考方案6】:
<div *ngFor="let number of [].constructor(myCollection)">
    <div>
        Hello World
    </div>
</div>

这是在 myCollection 中重复多次的好方法。

所以如果 myCollection 为 5,Hello World 将重复 5 次。

【讨论】:

我喜欢这个解决方案,因为不要触摸组件。谢谢!【参考方案7】:

也可以这样实现:

HTML:

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

打字稿:

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

Working Demo

【讨论】:

不要这样做,方法 fakeArray 将在每次更改检测时调用。如果您想在这样的模板中使用方法,则可以使用纯管道。【参考方案8】:

由于不带参数的 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);

【讨论】:

【参考方案9】:

你也可以这样使用

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>

【讨论】:

【参考方案10】:

我的解决方案:

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>

【讨论】:

这会在每次获取时创建一个新数组。可能会产生开销【参考方案11】:

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

怎么样:

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

这里我从一个空数组中获取Array 构造函数:[].constructor,因为Array 在模板语法中不是可识别的符号,我懒得做Array=Array 或@组件打字稿中的 987654326@ 就像 @pardeep-jain 在他的第四个示例中所做的那样。我在没有new 的情况下调用它,因为new 不是从Array 构造函数中取出数组所必需的。

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

数组将为空,但这并不重要,因为您真的只想在循环中使用来自;let i = indexi

【讨论】:

此解决方案触发更改检测。我猜是因为新的 Array。 @Tobias81,你能详细说明一下吗?您是说每次应用程序运行更改检测时,都会重新绘制 *ngFor 的内容,因为重新创建了数组?这绝对值得注意。可以通过在 TS 中实际创建一个数组字段来引用它,这样每次更改检测运行时它都是相同的。但这肯定不如预期的那么优雅。 Thierry Templier 选择的答案中的第二个示例中是否存在相同的更改检测问题? &lt;li *ngFor="let number of [0,1,2,3,4]"&gt;number&lt;/li&gt; @Tobias81,我已经检查以确保更改检测不会重复重新创建 ngFor 的内容,方法是将 print 语句放在我作为子组件创建的组件的构造函数中例如 ngFor 指令。我没有看到每次变更检测迭代都重新创建组件,所以我认为实际上没有问题(至少在 Angular 8 中)。 使用硬编码值效果很好,但是当我尝试使用变量时,它没有按预期工作。如果你能举个例子说明如何使用一个很棒的变量【参考方案12】:

我尝试过的最简单的方法

你也可以在你的组件文件中创建一个数组,你可以用 *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>

【讨论】:

&lt;div *ngfor="let i of 4, i++"&gt;&lt;/div&gt;的html有什么办法可以【参考方案13】:

我使用 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);

为了简洁而故意省略了错误检查和断言(例如,如果 step 为负数会发生什么)。

【讨论】:

&lt;div *ngfor="let i of 4, i++"&gt;&lt;/div&gt;的html有什么办法可以【参考方案14】:

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

请参阅此链接以创建数组:Tersest way to create an array of integers from 1..20 in javascript

然后您可以使用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 
  (...)

【讨论】:

是的,蒂埃里!确实,这不是你的错,但仍然在相同的上下文中:( 这一点都不优雅。但由于你是一个非常熟练的 A2 开发人员,我可以假设没有更好的解决方案。这很可悲! 其实在 Angular2 的循环语法中并没有这方面的内容。您需要利用 JavaScript 提供的功能来构建数组。例如:Array(5).fill(4) 创建[4,4,4,4,4] PS:在 angular2 beta 10 及更高版本中,@View 注解已被移除。 在 Angular 2 Typescript 中使用 Array.fill() 会产生以下错误 Supplied parameters do not match any signature of call t arget. — 检查 Array.prototype.fill 文档,它说它需要 1 个参数... developer.mozilla.org/en/docs/Web/JavaScript/Reference/… Array(5).fill(1).map((x, i) =&gt; i + 1); /*[1,2,3,4,5]*/这解决了TS中的错误【参考方案15】:

如果您想在单击按钮后动态增加数组的大小,请查看附件中的动态解决方案(这就是我提出这个问题的方式)。

必要变量的分配:

  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>

【讨论】:

&lt;div *ngfor="let i of 4, i++"&gt;&lt;/div&gt;的html有什么办法可以 你必须遍历一个数组。如果您需要标量,您可以迭代具有正确大小的数组并另外实例化一个标量: *ngFor="let item of array; let i = index"【参考方案16】:

你可以使用 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);

我没有测试代码,但它应该可以工作。

【讨论】:

&lt;div *ngfor="let i of 4, i++"&gt;&lt;/div&gt;的html有没有办法可以 如果您需要i 或索引代码,那么您可以使用*ngFor="let i of range; let i = index"【参考方案17】:

我无法忍受为组件的简单重复分配数组的想法,所以我编写了一个结构指令。在最简单的形式中,它不会使索引对模板可用,它看起来像这样:

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

【讨论】:

我同意数组方法很难看,但这对我来说似乎是过早的优化。 当然,也是编写指令的练习。另一方面,它不比管道长,这是第二种理智的方法。 这很好,没有太多机会让您了解自定义结构指令的概念。 不错的@pdudits - 仍然适用于最新版本:plnkr.co/edit/8wJtkpzre3cBNokHcDL7?p=preview [随时更新您的 plnkr]

以上是关于Angular 2 - NgFor 使用数字而不是集合的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2:将 *ngFor 增加 2 或在分页中实现两个分页

Angular ngFor 生命周期

Angular2 ngFor如何计算循环值的数量?

ngFor 中的 Angular2 组件抛出错误(viewFactory 不是函数)

Angular 有效地使用 trackBy 和 ngFor

使用 *ngFor 的 Angular 2 第一项在数组中丢失