personalizadas formularios example directivas angular

angular - formularios - Repita el elemento HTML varias veces usando ngFor basado en un número



ngfor angular 4 example (10)

Aquí hay una versión ligeramente mejorada de la directiva estructural de Ilyass Lamrani que le permite usar el índice en su plantilla:

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

Uso:

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

¿Cómo uso *ngFor para repetir un elemento HTML varias veces?

Por ejemplo: si tengo una variable miembro asignada a 20. ¿Cómo uso la directiva * ngFor para hacer que un div se repita 20 veces?


Enfoque más simple:

Defina una matriz auxiliar y ejemplifique dinámicamente (o estática si lo desea) con la longitud del recuento con el que desea crear sus elementos HTML. Por ejemplo, quiero obtener algunos datos del servidor y crear elementos con la longitud de la matriz que se devuelve.

export class AppComponent { helperArray: Array<any>; constructor(private ss: StatusService) { } ngOnInit(): void { this.ss.getStatusData().subscribe((status: Status[]) => { this.helperArray = new Array(status.length); }); } }

Luego use el helperArray en mi plantilla HTML.

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


Hay dos problemas con las soluciones recomendadas con Arrays :

  1. Es un desperdicio. En particular para grandes números.
  2. Debe definirlos en algún lugar que genere un montón de desorden para una operación tan simple y común.

Parece más eficiente definir una Pipe (una vez), devolviendo 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; } }

Ejemplo de uso (renderizar una cuadrícula con ancho / alto dinámico):

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


La forma más eficiente y concisa de lograr esto es agregando una utilidad de iterador. No te molestes en ceder valores. No se moleste en establecer una variable en la directiva 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; }


Puedes usar lo siguiente:

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

O implemente una tubería personalizada:

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


Si está utilizando Lodash , puede hacer lo siguiente:

Importa Lodash a tu componente.

import * as _ from "lodash";

Declare una variable miembro dentro del componente para hacer referencia a Lodash.

lodash = _;

Luego, desde su punto de vista, puede usar la función de rango . 20 puede ser reemplazado por cualquier variable en su componente.

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

Debe decirse que enlazar a funciones en la vista puede ser costoso, dependiendo de la complejidad de la función que está llamando, ya que la detección de cambios llamará a la función repetidamente.


Simplemente puede hacer esto en su HTML:

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

Y use la variable "número" para indexar.


Una solución más simple y reutilizable puede ser usar una directiva estructural personalizada como esta.

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

Y úsalo así:

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


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

Reemplace 20 con su variable


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

genera 🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱🐱