Повторить элемент HTML несколько раз, используя ngFor на основе числа


104

Как использовать *ngForдля повторения элемента HTML несколько раз?

Например: если мне присвоена переменная-член 20. Как использовать директиву * ngFor, чтобы div повторялся 20 раз?



Есть четыре способа добиться того же, читайте здесь. stackoverflow.com/a/36356629/5043867
Пардип Джайн

Ответы:


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
Да, ты прав! Так лучше ;-) Спасибо, что указали на это. Я соответствующим образом обновил свой ответ ...
Тьерри Темплиер

6
В первом подходе, я думаю, вы хотели сказать arr=Array;?
Абдулрахман Альсогайер

3
вы можете сделать кодовый ключ? это не работает: self.parentView.context.arr не является функцией
Toolkit

1
Спасибо за первый подход! Я не использую .fill (1) и работаю;)
gtamborero

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

генерирует 🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱


11
Это должен быть правильный ответ .. Это, безусловно, самый краткий!
Mantisimo

ОШИБКА 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

Шикарное решение довольно неудобной задачи. Но я полагаю, это влияет на производительность для большого количества элементов?
Мартин Эклебен,

51

При использовании рекомендуемых решений возникают две проблемы Arrays:

  1. Это расточительно. В особенности для большого количества.
  2. Вы должны где-то определить их, что создает много помех для такой простой и распространенной операции.

Кажется более эффективным определить 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]"

И используйте переменную «число» для индексации.


1
OP сказал, что он назначил 20переменную-член .. так что это не сильно поможет
phil294

Что, если я хочу повторить 200 раз?
Chax

1
@Chax Ты не можешь. :(
Мухаммад бин Юсрат

2
@Chax Что не так с 200? *ngFor="let number of [0,1,2,3,4,5...,199,200]":-D
Stack

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>

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

Вот немного улучшенная версия структурной директивы Ильяса Ламрани, которая позволяет вам использовать индекс в вашем шаблоне:

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

0

Вы можете использовать это просто:

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 {}
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.