Répétez l'élément HTML plusieurs fois en utilisant ngFor en fonction d'un nombre


Réponses:


90

Vous pouvez utiliser les éléments suivants:

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

Ou implémentez un tube personnalisé:

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
la classe FillPipe doit implémenter PipeTransform
toumir

1
Oui tu as raison! C'est mieux ;-) Merci de l'avoir signalé. J'ai mis à jour ma réponse en conséquence ...
Thierry Templier

6
Dans la première approche, je pense que vous vouliez dire arr=Array;?
Abdulrahman Alsoghayer

3
pouvez-vous faire un codepen? cela ne fonctionne pas: self.parentView.context.arr n'est pas une fonction
Toolkit

1
Merci pour la première approche! Je n'utilise pas le .fill (1) et je travaille;)
gtamborero

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

Remplacez 20par votre variable


2
C'est certainement une excellente réponse
edkeveked

la répétition doit être 19; longueur-1.
Mert Mertce

Solution élégante pour un problème assez peu pratique. Mais je suppose que cela a un impact sur les performances pour un grand nombre d'éléments?
Martin Eckleben

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

génère 🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱


11
Cela devrait être la bonne réponse. C'est de loin la plus concise!
Mantisimo

ERROR RangeError: longueur de tableau non valide. Cela plantera lorsque le nombre de chats à dessiner sera nul.
Tom Bevelander

J'aime vraiment cette approche simple!
F. Geißler

51

Il y a deux problèmes avec les solutions recommandées en utilisant Arrays:

  1. C'est du gaspillage. En particulier pour les grands nombres.
  2. Vous devez les définir quelque part, ce qui entraîne beaucoup d'encombrement pour une opération aussi simple et courante.

Il semble plus efficace de définir un Pipe(une fois), en retournant un 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;
  }
}

Exemple d'utilisation (rendu d'une grille avec largeur / hauteur dynamique):

<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

Vous pouvez simplement le faire dans votre HTML:

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

Et utilisez la variable "nombre" pour indexer.


1
OP dit qu'il a assigné 20à une variable membre .. donc cela n'aidera pas beaucoup
phil294

Et si je veux répéter 200 fois?
Chax

1
@Chax Vous ne pouvez pas. :(
Muhammad bin Yusrat

2
@Chax Quel est le problème avec 200? *ngFor="let number of [0,1,2,3,4,5...,199,200]":-D
Stack Underflow

1
@StackUnderflow Malheureusement, je ne suis pas payé par les personnages. Si c'était le cas, je prêcherais que c'est le seul moyen d'y parvenir: P (sérieusement, ne le faites pas;))
Chax

10

Une solution plus simple et réutilisable peut-être d'utiliser une directive structurelle personnalisée comme celle-ci.

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

}

Et utilisez-le comme ceci:

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

pour plus d'informations: netbasal.com
Ilyass Lamrani

4

Le moyen le plus efficace et le plus concis d'y parvenir est d'ajouter un utilitaire d'itération. Ne vous embêtez pas à donner des valeurs. Ne vous embêtez pas à définir une variable dans la directive 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

Si vous utilisez Lodash , vous pouvez effectuer les opérations suivantes:

Importez Lodash dans votre composant.

import * as _ from "lodash";

Déclarez une variable membre dans le composant pour référencer Lodash.

lodash = _;

Ensuite, dans votre vue, vous pouvez utiliser la fonction de plage . 20 peut être remplacé par n'importe quelle variable de votre composant.

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

Il faut dire que la liaison à des fonctions dans la vue peut être coûteuse, selon la complexité de la fonction que vous appelez, car la détection de changement appellera la fonction à plusieurs reprises.


1

Vous n'avez pas besoin de remplir le tableau comme suggéré dans la plupart des réponses. Si vous utilisez index dans votre ngForboucle, il vous suffit de créer un tableau vide avec la longueur correcte:

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

et à votre avis:

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

0

Approche plus simple:

Définissez un helperArray et instanciez-le dynamiquement (ou statique si vous le souhaitez) avec la longueur du nombre que vous souhaitez créer vos éléments HTML. Par exemple, je souhaite obtenir des données du serveur et créer des éléments avec la longueur du tableau renvoyé.

export class AppComponent {
  helperArray: Array<any>;

  constructor(private ss: StatusService) {
  }

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

Ensuite, utilisez le helperArray dans mon modèle HTML.

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

0

Voici une version légèrement améliorée de la directive structurelle d'Ilyass Lamrani qui vous permet d'utiliser l'index dans votre modèle:

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

}

Usage:

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

0

Je sais que vous avez spécifiquement demandé de le faire en utilisant * ngFor, mais je voulais partager la façon dont j'ai résolu cela en utilisant une directive structurelle:

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

Avec cela, vous pouvez l'utiliser comme ceci:

<div *appRepeat="15">
  Testing
</div>

0

Vous pouvez utiliser ceci simplement:

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 {}
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.