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 = index
的i
。
【讨论】:
此解决方案触发更改检测。我猜是因为新的 Array。 @Tobias81,你能详细说明一下吗?您是说每次应用程序运行更改检测时,都会重新绘制 *ngFor 的内容,因为重新创建了数组?这绝对值得注意。可以通过在 TS 中实际创建一个数组字段来引用它,这样每次更改检测运行时它都是相同的。但这肯定不如预期的那么优雅。 Thierry Templier 选择的答案中的第二个示例中是否存在相同的更改检测问题?<li *ngFor="let number of [0,1,2,3,4]">number</li>
@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>
【讨论】:
<div *ngfor="let i of 4, i++"></div>
的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 为负数会发生什么)。
【讨论】:
<div *ngfor="let i of 4, i++"></div>
的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) => 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>
【讨论】:
<div *ngfor="let i of 4, i++"></div>
的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);
我没有测试代码,但它应该可以工作。
【讨论】:
<div *ngfor="let i of 4, i++"></div>
的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 或在分页中实现两个分页