ทำซ้ำองค์ประกอบ HTML หลาย ๆ ครั้งโดยใช้ ngFor ตามตัวเลข


108

ฉันจะใช้*ngForเพื่อทำองค์ประกอบ HTML ซ้ำหลาย ๆ ครั้งได้อย่างไร

ตัวอย่างเช่น: ถ้าฉันมีตัวแปรสมาชิกที่กำหนดให้เป็น 20 ฉันจะใช้คำสั่ง * ngFor เพื่อสร้าง div ซ้ำ 20 ครั้งได้อย่างไร



มีสี่วิธีในการบรรลุเป้าหมายเดียวกันอ่านได้ที่นี่ stackoverflow.com/a/36356629/5043867
Pardeep Jain

คำตอบ:


91

คุณสามารถใช้สิ่งต่อไปนี้:

@Component({
  (...)
  template: `
    <div *ngFor="let i of Arr(num).fill(1)"></div>
  `
})
export class SomeComponent {
  Arr = Array; //Array type captured in a variable
  num:number = 20;
}

หรือใช้ไปป์ที่กำหนดเอง:

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

@Pipe({
  name: 'fill'
})
export class FillPipe implements PipeTransform {
  transform(value) {
    return (new Array(value)).fill(1);
  }
}

@Component({
  (...)
  template: `
    <div *ngFor="let i of num | fill"></div>
  `,
  pipes: [ FillPipe ]
})
export class SomeComponent {
  arr:Array;
  num:number = 20;
}

1
คลาส FillPipe ต้องดำเนินการ PipeTransform
toumir

1
ใช่คุณพูดถูก! มันดีกว่า ;-) ขอบคุณที่ชี้ให้เห็น ฉันอัปเดตคำตอบตามนั้น ...
Thierry Templier

6
ในแนวทางแรกฉันคิดว่าคุณตั้งใจจะพูดarr=Array;?
Abdulrahman Alsoghayer

3
คุณสามารถสร้าง codepen ได้ไหม มันไม่ทำงาน: self.parentView.context.arr ไม่ใช่ฟังก์ชัน
Toolkit

1
ขอบคุณสำหรับแนวทางแรก! ฉันไม่ได้ใช้ .fill (1) และใช้งานได้;)
gtamborero

88
<ng-container *ngFor="let i of [].constructor(20)">🐱</ng-container>

สร้าง🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱


13
นี่น่าจะเป็นคำตอบที่ถูกต้อง .. เป็นคำตอบที่กระชับที่สุด!
Mantisimo

ERROR RangeError: ความยาวอาร์เรย์ไม่ถูกต้อง สิ่งนี้จะผิดพลาดเมื่อจำนวนแมวที่จะวาดเป็นศูนย์
Tom Bevelander

ชอบวิธีง่ายๆแบบนั้นจริงๆ!
F. Geißler

76
<div *ngFor="let dummy of ' '.repeat(20).split(''), let x = index">

แทนที่20ด้วยตัวแปรของคุณ


2
นี่เป็นคำตอบที่ดีอย่างแน่นอน
edkeveked

ทำซ้ำควรเป็น 19; ความยาว -1.
Mert Mertce

ทางออกที่สวยงามสำหรับปัญหาที่ค่อนข้างไม่สะดวก แต่ฉันเดาว่ามันมีผลต่อประสิทธิภาพสำหรับองค์ประกอบจำนวนมาก?
Martin Eckleben

52

มีปัญหาสองประการในแนวทางแก้ไขที่แนะนำโดยใช้Arrays:

  1. มันสิ้นเปลือง. โดยเฉพาะอย่างยิ่งสำหรับจำนวนมาก
  2. คุณต้องกำหนดไว้ที่ใดที่หนึ่งซึ่งส่งผลให้เกิดความยุ่งเหยิงมากมายสำหรับการดำเนินการที่เรียบง่ายและทั่วไป

ดูเหมือนว่าจะมีประสิทธิภาพมากขึ้นในการกำหนด a Pipe(ครั้งเดียว) โดยส่งคืนIterable:

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

@Pipe({name: 'times'})
export class TimesPipe implements PipeTransform {
  transform(value: number): any {
    const iterable = <Iterable<any>> {};
    iterable[Symbol.iterator] = function* () {
      let n = 0;
      while (n < value) {
        yield ++n;
      }
    };
    return iterable;
  }
}

ตัวอย่างการใช้งาน (การแสดงตารางที่มีความกว้าง / ความสูงแบบไดนามิก):

<table>
    <thead>
      <tr>
        <th *ngFor="let x of colCount|times">{{ x }}</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let y of rowCount|times">
        <th scope="row">{{ y }}</th>
        <td *ngFor="let x of colCount|times">
            <input type="checkbox" checked>
        </td>
      </tr>
    </tbody>
</table>

26

คุณสามารถทำได้ง่ายๆใน HTML ของคุณ:

*ngFor="let number of [0,1,2,3,4,5...,18,19]"

และใช้ตัวแปร "number" เพื่อจัดทำดัชนี


1
OP บอกว่าเขากำหนด20ให้ตัวแปรสมาชิก .. ดังนั้นสิ่งนี้จะช่วยไม่ได้มากนัก
phil294

จะทำอย่างไรถ้าฉันต้องการทำซ้ำ 200 ครั้ง?
Chax

1
@Chax คุณไม่สามารถ :(
มูฮัมหมัดบินยุสรัต

3
@Chax 200 ผิดอะไร? *ngFor="let number of [0,1,2,3,4,5...,199,200]":-D
Stack Underflow

1
@StackUnderflow น่าเศร้าที่ฉันไม่ได้รับเงินจากตัวละคร ถ้าฉันเป็นฉันจะเทศน์ว่ามันเป็นวิธีเดียวที่จะบรรลุสิ่งนั้น: P (อย่างจริงจังก็อย่า;))
Chax

10

วิธีแก้ปัญหาที่ง่ายกว่าและใช้ซ้ำได้อาจใช้คำสั่งโครงสร้างแบบกำหนดเองเช่นนี้

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appTimes]'
})
export class AppTimesDirective {

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef) { }

  @Input() set appTimes(times: number) {
    for (let i = 0 ; i < times ; i++) {
      this.viewContainer.createEmbeddedView(this.templateRef);
    }
  }

}

และใช้มันดังนี้:

<span *appTimes="3" class="fa fa-star"></span>

ข้อมูลเพิ่มเติม: netbasal.com/…
Ilyass Lamrani

4

วิธีที่มีประสิทธิภาพและรัดกุมที่สุดในการบรรลุเป้าหมายนี้คือการเพิ่มโปรแกรมอรรถประโยชน์ตัววนซ้ำ อย่ากังวลกับการยอมรับคุณค่า อย่ากังวลกับการตั้งค่าตัวแปรในคำสั่ง ngFor:

function times(max: number) {
  return {
    [Symbol.iterator]: function* () {
      for (let i = 0; i < max; i++, yield) {
      }
    }
  };
}

@Component({
  template: ```
<ng-template ngFor [ngForOf]="times(6)">
  repeats 6 times!
</ng-template>

```
})
export class MyComponent {
  times = times;
}

1

หากคุณใช้Lodashคุณสามารถทำสิ่งต่อไปนี้:

นำเข้าLodashไปยังส่วนประกอบของคุณ

import * as _ from "lodash";

ประกาศตัวแปรสมาชิกภายในองค์ประกอบเพื่ออ้างอิง Lodash

lodash = _;

จากนั้นในมุมมองของคุณคุณสามารถใช้ฟังก์ชั่นหลากหลาย 20 สามารถแทนที่ด้วยตัวแปรใดก็ได้ในองค์ประกอบของคุณ

*ngFor="let number of lodash.range(20)"

ต้องบอกว่าการเชื่อมโยงกับฟังก์ชันในมุมมองอาจมีค่าใช้จ่ายสูงขึ้นอยู่กับความซับซ้อนของฟังก์ชันที่คุณเรียกใช้เนื่องจากการตรวจจับการเปลี่ยนแปลงจะเรียกใช้ฟังก์ชันซ้ำ ๆ


1

คุณไม่จำเป็นต้องเติมอาร์เรย์เหมือนที่แนะนำในคำตอบส่วนใหญ่ หากคุณใช้ดัชนีในngForลูปสิ่งที่คุณต้องสร้างคืออาร์เรย์ว่างที่มีความยาวที่ถูกต้อง:

const elements = Array(n); // n = 20 in your case

และในมุมมองของคุณ:

<li *ngFor="let element in elements; let i = index">
  <span>{{ i }}</span>
</li>

1

คุณสามารถใช้สิ่งนี้ได้ง่ายๆ:

HTML

<div *ngFor="let i of Count">

TS

export class Component implements OnInit {
  Count = [];

  constructor() {
    this.Count.length = 10; //you can give any number
  }

  ngOnInit(): void {}
}

0

แนวทางที่ง่ายกว่า:

กำหนด helperArray และสร้างอินสแตนซ์แบบไดนามิก (หรือคงที่ถ้าคุณต้องการ) ด้วยความยาวของการนับที่คุณต้องการสร้างองค์ประกอบ HTML ของคุณ ตัวอย่างเช่นฉันต้องการรับข้อมูลบางส่วนจากเซิร์ฟเวอร์และสร้างองค์ประกอบที่มีความยาวของอาร์เรย์ที่ส่งคืน

export class AppComponent {
  helperArray: Array<any>;

  constructor(private ss: StatusService) {
  }

  ngOnInit(): void {
    this.ss.getStatusData().subscribe((status: Status[]) => {
      this.helperArray = new Array(status.length);
    });
  }
}

จากนั้นใช้ helperArray ในเทมเพลต HTML ของฉัน

<div class="content-container" *ngFor="let i of helperArray">
  <general-information></general-information>
  <textfields></textfields>
</div>

0

ต่อไปนี้เป็นคำสั่งโครงสร้างของ Ilyass Lamrani เวอร์ชันปรับปรุงเล็กน้อยที่ช่วยให้คุณใช้ดัชนีในเทมเพลตของคุณ:

@Directive({
  selector: '[appRepeatOf]'
})
export class RepeatDirective {

  constructor(private templateRef: TemplateRef<any>,
              private viewContainer: ViewContainerRef) {
  }

  @Input()
  set appRepeatOf(times: number) {
    const initialLength = this.viewContainer.length;
    const diff = times - initialLength;

    if (diff > 0) {
      for (let i = initialLength; i < initialLength + diff; i++) {
        this.viewContainer.createEmbeddedView(this.templateRef, {
          $implicit: i
        });
      }
    } else {
      for (let i = initialLength - 1; i >= initialLength + diff ; i--) {
      this.viewContainer.remove(i);
    }
  }

}

การใช้งาน:

<li *appRepeat="let i of myNumberProperty">
    Index: {{i}}
</li>

0

ฉันรู้ว่าคุณขอให้ทำโดยใช้ * ngFor เป็นพิเศษ แต่ฉันต้องการแบ่งปันวิธีที่ฉันแก้ไขโดยใช้คำสั่งโครงสร้าง:

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({ selector: '[appRepeat]' })
export class RepeatDirective {
  constructor(private templateRef: TemplateRef<any>, private viewContainerRef: ViewContainerRef) {
  }

  @Input() set appRepeat(loops: number) {
    for (let index = 0; index < loops; ++index) {
      this.viewContainerRef.createEmbeddedView(this.templateRef);
    }
  }
}

ด้วยสิ่งนี้คุณสามารถใช้งานได้ดังนี้:

<div *appRepeat="15">
  Testing
</div>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.