Angular 2 - NgFor sử dụng số thay vì bộ sưu tập


190

...ví dụ...

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

Có thể làm một cái gì đó như ...

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

... Không có sự hấp dẫn đối với một giải pháp không thanh lịch như:

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

?


8
Tôi có cùng một vấn đề. Thật sự khó chịu người ta không thể làm những điều đơn giản như vậy với góc 2.
albanx

1
Có lẽ điều này có thể hữu ích: stackoverflow.com/questions/3895478/ từ
Pizzicato

Câu trả lời:


195

Trong thành phần của bạn, bạn có thể xác định một mảng số (ES6) như được mô tả dưới đây:

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

Xem liên kết này để tạo mảng: Cách tốt nhất để tạo một mảng các số nguyên từ 1..20 trong JavaScript .

Sau đó, bạn có thể lặp lại mảng này với ngFor:

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

Hoặc ngắn gọn:

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

5
Vâng, Thierry! Thực sự đó không phải là lỗi của bạn, nhưng vẫn trong cùng một bối cảnh :( Nó không thanh lịch chút nào. Nhưng vì bạn là một nhà phát triển A2 rất lành nghề, tôi có thể cho rằng không có giải pháp nào tốt hơn. Thật đáng buồn!
Marco Jr

Trong thực tế, không có gì cho điều này trong Angular2 trong cú pháp vòng lặp. Bạn cần tận dụng những gì JavaScript cung cấp để xây dựng mảng. Ví dụ: Array(5).fill(4)để tạo[4,4,4,4,4]
Thierry Templier

3
PS: Chú thích @View đã bị xóa trong angular2 beta 10 trở lên.
Pardeep Jain

23
Việc sử dụng Array.fill()trong Angular 2 Typecript tạo ra lỗi sau Supplied parameters do not match any signature of call t arget.- Kiểm tra tài liệu Array.prototype.fill, nó nói rằng nó yêu cầu 1 đối số ... developer.mozilla.org/en/docs/Web/JavaScript/Reference/
tựa

5
Array(5).fill(1).map((x, i) => i + 1); /*[1,2,3,4,5]*/điều này giải quyết lỗi trong TS
mshahbazm

85

@OP, bạn đã rất gần với giải pháp "không thanh lịch" của mình.

Làm thế nào về:

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

Ở đây tôi nhận được hàm Arraytạo từ một mảng trống : [].constructor, vì Arraykhông phải là biểu tượng được nhận dạng trong cú pháp mẫu và tôi quá lười để làmArray=Array hoặc counter = Arraytrong bản thảo thành phần như @ pardeep-jain đã làm trong ví dụ thứ 4 của mình. Và tôi đang gọi nó mà không cần thiết newnewkhông cần thiết phải lấy một mảng ra khỏi hàm Arraytạo.

Array(30)new Array(30)là tương đương.

Mảng sẽ trống, nhưng điều đó không quan trọng bởi vì bạn thực sự chỉ muốn sử dụng itừ ;let i = indextrong vòng lặp của mình.


11
Đây là câu trả lời tốt nhất.
kagronick

Giải pháp này kích hoạt phát hiện thay đổi. Tôi đoán do mảng mới.
Tobias81

1
@ Tobias81, bạn có thể giải thích? Bạn có nói rằng mỗi khi ứng dụng chạy phát hiện thay đổi, nội dung của * ngFor sẽ được vẽ lại vì mảng được tạo lại? Đó chắc chắn là đáng chú ý. Người ta có thể khắc phục nó bằng cách thực sự tạo một trường mảng trong TS để tham chiếu sao cho giống nhau mỗi lần phát hiện thay đổi chạy. Nhưng điều đó chắc chắn sẽ kém thanh lịch hơn mong muốn. Có phải vấn đề phát hiện thay đổi tương tự có trong ví dụ thứ 2 trong câu trả lời được chọn của Thierry Templier không? <li *ngFor="let number of [0,1,2,3,4]">{{number}}</li>
jcairney

đây là giải pháp tốt nhất cho vấn đề này
khush

1
@ Tobias81, tôi đã kiểm tra để đảm bảo phát hiện thay đổi không tạo lại nội dung của ngFor nhiều lần, bằng cách đặt một câu lệnh in bên trong hàm tạo của một thành phần mà tôi tạo như một phần tử của lệnh ngFor ví dụ. Tôi không thấy các thành phần được tạo lại trên mỗi lần lặp Phát hiện thay đổi, vì vậy tôi không nghĩ thực sự có vấn đề (ít nhất là trong Angular 8).
jcairney

83

Không có phương pháp nào cho NgFor sử dụng các số thay vì các bộ sưu tập, Hiện tại, * ngFor chỉ chấp nhận một bộ sưu tập làm tham số, nhưng bạn có thể thực hiện điều này bằng các phương pháp sau:

Sử dụng đường ống

ống.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>

Sử dụng mảng số trực tiếp trong HTML (Xem)

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

Sử dụng phương pháp Split

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

Sử dụng tạo mảng mới trong thành phần

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

Bản demo làm việc


4
Bạn cũng có thể sử dụng Array.fill()phương thức để tạo mảng thay vì res.push()như trong câu trả lời của Thierrys.
Günter Zöchbauer

vâng tôi có thể nhưng có gì sai với push ? tôi có nghĩa là cả hai phương pháp đều đúng nhưng vẫn nếu có khác. giữa họ.
Pardeep Jain

3
Không, vẫn là một giải pháp tốt đẹp +1. Tôi chỉ thấy Array.fill()thanh lịch hơn vòng lặp sử dụng đẩy và nó có lẽ cũng hiệu quả hơn.
Günter Zöchbauer

1
Tôi thích giải pháp này với counter = Array, rất thông minh;)
Verri

11

Tôi không thể chịu được ý tưởng phân bổ một mảng để lặp lại các thành phần đơn giản, vì vậy tôi đã viết một chỉ thị cấu trúc. Ở dạng đơn giản nhất, điều đó không làm cho chỉ mục có sẵn cho mẫu, nó trông như thế này:

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


Tôi đồng ý cách tiếp cận mảng là xấu, nhưng điều này có vẻ như tối ưu hóa sớm đối với tôi.
Aluan Haddad

3
Tất nhiên, nhưng cũng là một bài tập trong việc viết một chỉ thị. Mặt khác, nó không dài hơn đường ống, đó sẽ là cách tiếp cận lành mạnh thứ hai.
pdudits

Đó là một điểm tốt, không có nhiều cơ hội để có được một số của bạn với khái niệm về các chỉ thị cấu trúc tùy chỉnh.
Aluan Haddad

Nice one @pdudits - Vẫn làm việc với phiên bản mới nhất: plnkr.co/edit/8wJtkpzre3cBNokHcDL7?p=preview [cảm thấy tự do để cập nhật plnkr của bạn]
AT

5

Tôi đã giải quyết nó như thế này bằng Angular 5.2.6 và 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);
}

Nó có thể được sử dụng trong Thành phần như thế này:

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

Kiểm tra lỗi và xác nhận bỏ qua nhằm mục đích cho sự ngắn gọn (ví dụ: điều gì xảy ra nếu bước âm).


2
Có cách nào trong html như <div *ngfor="let i of 4, i++"></div>có thể được không
Nithila Shanmugananthan

5

bạn cũng có thể sử dụng như thế

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

Bạn có thể sử dụng 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);
}

Tôi đã không kiểm tra mã nhưng nó sẽ hoạt động.


Có cách nào trong html như <div *ngfor="let i of 4, i++"></div>có thể được không
Nithila Shanmugananthan

Nếu bạn cần ihoặc lập chỉ mục trong một mã thì bạn có thể làm*ngFor="let i of range; let i = index"
Alex Po

3

Điều này cũng có thể đạt được như thế này:

HTML:

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

Bản thảo:

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

Trình diễn làm việc


2

Vì phương thức fill () (được đề cập trong câu trả lời được chấp nhận) không có đối số gây ra lỗi, tôi sẽ đề xuất một cái gì đó như thế này (hoạt động với tôi, Angular 7.0.4, Bản đánh máy 3.1.6)

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

Trong mã thành phần:

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

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

Đây là một cách hay và nhanh chóng để lặp lại số lần trong myCollection.

Vì vậy, nếu myCollection là 5, Hello World sẽ được lặp lại 5 lần.


1

Sử dụng Chỉ thị cấu trúc tùy chỉnh với chỉ mục:

Theo tài liệu Angular:

createEmbeddedView Khởi tạo một khung nhìn được nhúng và chèn nó vào thùng chứa này.

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.

Khi angular tạo mẫu bằng cách gọi createdEmbeddedView, nó cũng có thể chuyển ngữ cảnh sẽ được sử dụng bên trong ng-template.

Sử dụng tham số tùy chọn ngữ cảnh, bạn có thể sử dụng nó trong thành phần, trích xuất nó trong mẫu giống như bạn làm với * 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

Vui lòng tìm giải pháp động đính kèm của tôi nếu bạn muốn tăng kích thước của mảng một cách linh hoạt sau khi nhấp vào nút (Đây là cách tôi nhận được câu hỏi này).

Phân bổ các biến cần thiết:

  array = [1];
  arraySize: number;

Khai báo hàm thêm một phần tử vào mảng:

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

Gọi hàm trong html

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

Lặp lại qua mảng với ngFor:

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

Có cách nào trong html như <div *ngfor="let i of 4, i++"></div>có thể được không
Nithila Shanmugananthan

bạn phải lặp đi lặp lại qua một mảng. Nếu bạn cần vô hướng, bạn có thể lặp qua một mảng với kích thước phù hợp và thêm vào một vô hướng: * ngFor = "let item of Array; let i = index"
Jan Clemens Stoffregen

0

Một cách đơn giản nhất mà tôi đã thử

Bạn cũng có thể tạo một mảng trong tệp thành phần của mình và bạn có thể gọi nó bằng * ngFor directive bằng cách quay lại dưới dạng một mảng.

Một cái gì đó như thế này ....

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

}

Và chức năng này có thể được sử dụng trong tệp mẫu html của bạn

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

2
Có cách nào trong html như <div *ngfor="let i of 4, i++"></div>có thể được không
Nithila Shanmugananthan

0

Giải pháp của tôi:

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

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

điều này tạo ra một mảng mới trên mỗi get. Có thể tạo ra chi phí
Remco Vlierman
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.