Повторіть HTML-елемент кілька разів, використовуючи ngFor на основі числа


103

Як я можу *ngForповторювати HTML-елемент кілька разів?

Наприклад: Якщо у мене змінна члена присвоюється 20. Як я можу використовувати директиву * ngFor, щоб зробити повтор діва 20 разів?


1
Дивіться також stackoverflow.com/questions/47586525 / ...
yurzui

Про це можна прочитати чотири способи , читайте тут. stackoverflow.com/a/36356629/5043867
Pardeep Jain

Відповіді:


90

Ви можете використовувати наступне:

@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

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

Замініть 20свою змінну


2
Це, безумовно, чудова відповідь
edkeveked

повтор повинен бути 19; довжина-1.
Мерт Мерце

Елегантне рішення досить незручної проблеми. Але я думаю, що це впливає на ефективність для великої кількості елементів?
Мартін Еклебен

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

породжує 🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱


11
Це має бути правильна відповідь. Це, безумовно, найбільш стислий!
Mantisimo

ERROR RangeError: Недійсна довжина масиву. Це призведе до краху, коли кількість котів, які малюють, дорівнює нулю.
Том

Дуже подобається той простий підхід!
Ф. Гейслер

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
ОП заявив, що присвоїв 20змінну члена. Тому це не дуже допоможе
phil294

Що робити, якщо я хочу повторити 200 разів?
Чакс

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

Ось дещо вдосконалена версія структурної директиви 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>

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.