Powtórz element HTML wiele razy, używając ngFor na podstawie liczby

Odpowiedzi:

90

Możesz użyć następujących:

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

Lub zaimplementuj niestandardową rurę:

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;
}
Thierry Templier
źródło
1
klasa FillPipe musi implementować PipeTransform
toumir
1
Tak, masz rację! Jest lepiej ;-) Dzięki za zwrócenie uwagi. Odpowiednio zaktualizowałem moją odpowiedź ...
Thierry Templier
6
Myślę, że w pierwszym podejściu chciałeś powiedzieć arr=Array;?
Abdulrahman Alsoghayer
3
czy możesz zrobić kodepen? to nie działa: self.parentView.context.arr nie jest funkcją
zestaw narzędzi
1
Dzięki za pierwsze podejście! Nie używam .fill (1) i działa;)
gtamborero
76
<div *ngFor="let dummy of ' '.repeat(20).split(''), let x = index">

Zastąp 20swoją zmienną

Aximili
źródło
2
To zdecydowanie świetna odpowiedź
edkeveked
powtórzenie powinno wynosić 19; długość-1.
Mert Mertce
Eleganckie rozwiązanie dość niewygodnego problemu. Ale myślę, że ma to wpływ na wydajność dla dużej liczby elementów?
Martin Eckleben
76
<ng-container *ngFor="let i of [].constructor(20)">🐱</ng-container>

generuje 🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱

ttulka
źródło
11
To powinna być prawidłowa odpowiedź. Jest zdecydowanie najbardziej zwięzła!
Mantisimo
ERROR RangeError: Nieprawidłowa długość tablicy. Spowoduje to awarię, gdy liczba kotów do narysowania wynosi zero.
Tom Bevelander
Naprawdę lubię to proste podejście!
F. Geißler
51

Istnieją dwa problemy z zalecanymi rozwiązaniami przy użyciu Arrays:

  1. To marnotrawstwo. W szczególności w przypadku dużych ilości.
  2. Trzeba je gdzieś zdefiniować, co skutkuje dużym bałaganem przy tak prostej i powszechnej operacji.

Wydaje się bardziej efektywne zdefiniowanie a Pipe(raz), zwracając 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;
  }
}

Przykład zastosowania (renderowanie siatki z dynamiczną szerokością / wysokością):

<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>
Andreas Baumgart
źródło
26

Możesz to łatwo zrobić w swoim HTML:

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

I użyj zmiennej „numer” do indeksowania.

Dekonunes
źródło
1
OP powiedział, że przypisał 20zmienną składową ... więc to niewiele pomoże
phil294,
A jeśli chcę powtórzyć 200 razy?
Chax
1
@Chax Nie możesz. :(
Muhammad bin Yusrat
2
@Chax Co jest nie tak z 200? *ngFor="let number of [0,1,2,3,4,5...,199,200]":-D
Stack Underflow,
1
@StackUnderflow Niestety nie płacą mi postacie. Gdybym był, głosiłbym, że to jedyny sposób, aby to osiągnąć: P (serio, po prostu nie;))
Chax
10

Prostsze i nadające się do wielokrotnego użytku rozwiązanie może używać niestandardowej dyrektywy strukturalnej, takiej jak ta.

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

}

I użyj tego w ten sposób:

<span *appTimes="3" class="fa fa-star"></span>
Ilyass Lamrani
źródło
więcej informacji: netbasal.com/…
Ilyass Lamrani
4

Najbardziej wydajnym i zwięzłym sposobem osiągnięcia tego jest dodanie narzędzia iteratora. Nie przejmuj się podawaniem wartości. Nie przejmuj się ustawieniem zmiennej w dyrektywie 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;
}
Amit Portnoy
źródło
1

Jeśli korzystasz z Lodash , możesz wykonać następujące czynności:

Importuj Lodash do swojego komponentu.

import * as _ from "lodash";

Zadeklaruj zmienną składową w komponencie, aby odwoływać się do Lodash.

lodash = _;

Wtedy, twoim zdaniem, możesz użyć funkcji zakresu . 20 można zastąpić dowolną zmienną w komponencie.

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

Trzeba powiedzieć, że powiązanie z funkcjami w widoku może być kosztowne, w zależności od złożoności funkcji, którą wywołujesz, ponieważ funkcja wykrywania zmian będzie wywoływać tę funkcję wielokrotnie.

Davy
źródło
1

Nie musisz wypełniać tablicy, jak sugerowano w większości odpowiedzi. Jeśli używasz indeksu w swojej ngForpętli, wszystko, co musisz utworzyć, to pusta tablica o odpowiedniej długości:

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

i Twoim zdaniem:

<li *ngFor="let element in elements; let i = index">
  <span>{{ i }}</span>
</li>
Więdnąć
źródło
0

Prostsze podejście:

Zdefiniuj helperArray i utwórz jego wystąpienie dynamicznie (lub statycznie, jeśli chcesz) z długością liczby, którą chcesz utworzyć elementy HTML. Na przykład chcę pobrać dane z serwera i utworzyć elementy o długości zwracanej tablicy.

export class AppComponent {
  helperArray: Array<any>;

  constructor(private ss: StatusService) {
  }

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

Następnie użyj helperArray w moim szablonie HTML.

<div class="content-container" *ngFor="let i of helperArray">
  <general-information></general-information>
  <textfields></textfields>
</div>
Florian Leitgeb
źródło
0

Oto nieco ulepszona wersja dyrektywy strukturalnej Ilyass Lamrani, która pozwala na użycie indeksu w szablonie:

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

}

Stosowanie:

<li *appRepeat="let i of myNumberProperty">
    Index: {{i}}
</li>
MK10
źródło
0

Wiem, że poprosiłeś o zrobienie tego za pomocą * ngFor, ale chciałem podzielić się sposobem, w jaki rozwiązałem to za pomocą dyrektywy strukturalnej:

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

Dzięki temu możesz go używać tak po prostu:

<div *appRepeat="15">
  Testing
</div>
Javier Campón
źródło
0

Możesz użyć tego po prostu:

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 {}
}
Janitha Rasanga
źródło