Saltar al contenido

Cómo agregar y eliminar dinámicamente campos de formulario en Angular 2

Solución:

Esto es unos meses tarde, pero pensé en proporcionar mi solución basada en este tutorial. La esencia es que es mucho más fácil de administrar una vez que cambia la forma en que aborda los formularios.

Primer uso ReactiveFormsModule en lugar de o además de lo normal FormsModule. Con los formularios reactivos, crea sus formularios en sus componentes / servicios y luego los conecta a su página en lugar de que su página genere el formulario en sí. Es un poco más de código, pero es mucho más comprobable, mucho más flexible y, por lo que puedo decir, es la mejor manera de hacer muchas formas no triviales.

El resultado final se verá un poco así, conceptualmente:

  • Tienes una base FormGroup con lo que sea FormControl instancias que necesita para la totalidad del formulario. Por ejemplo, como en el tutorial al que me vinculé, digamos que desea un formulario en el que un usuario pueda ingresar su nombre una vez y luego cualquier número de direcciones. Todas las entradas de campo de una sola vez estarían en este grupo de formulario base.

  • Dentro de eso FormGroup instancia habrá uno o más FormArray instancias. A FormArray es básicamente una forma de agrupar varios controles e iterar sobre ellos. También puede poner varios FormGroup instancias en su matriz y utilícelas esencialmente como “mini-formas” anidadas dentro de su forma más grande.

  • Anidando múltiples FormGroup y / o FormControl instancias dentro de una dinámica FormArray, puede controlar la validez y gestionar la forma como una pieza grande y reactiva compuesta por varias partes dinámicas. Por ejemplo, si desea comprobar si todas las entradas son válidas antes de permitir que el usuario envíe, la validez de un subformulario “aumentará” al formulario de nivel superior y todo el formulario dejará de ser válido, lo que facilitará la gestionar entradas dinámicas.

  • Como un FormArray es, esencialmente, un envoltorio alrededor de una interfaz de matriz, pero para piezas de formulario, puede presionar, extraer, insertar y eliminar controles en cualquier momento sin volver a crear el formulario o realizar interacciones complejas.

En caso de que el tutorial al que me vincule no funcione, aquí hay un código de muestra que puede implementar usted mismo (mis ejemplos usan TypeScript) que ilustran las ideas básicas:

Código de componente base:

import { Component, Input, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'my-form-component',
  templateUrl: './my-form.component.html'
})
export class MyFormComponent implements OnInit {
    @Input() inputArray: ArrayType[];
    myForm: FormGroup;

    constructor(private fb: FormBuilder) {}
    ngOnInit(): void {
        let newForm = this.fb.group({
            appearsOnce: ['InitialValue', [Validators.required, Validators.maxLength(25)]],
            formArray: this.fb.array([])
        });

        const arrayControl = <FormArray>newForm.controls['formArray'];
        this.inputArray.forEach(item => {
            let newGroup = this.fb.group({
                itemPropertyOne: ['InitialValue', [Validators.required]],
                itemPropertyTwo: ['InitialValue', [Validators.minLength(5), Validators.maxLength(20)]]
            });
            arrayControl.push(newGroup);
        });

        this.myForm = newForm;
    }
    addInput(): void {
        const arrayControl = <FormArray>this.myForm.controls['formArray'];
        let newGroup = this.fb.group({

            /* Fill this in identically to the one in ngOnInit */

        });
        arrayControl.push(newGroup);
    }
    delInput(index: number): void {
        const arrayControl = <FormArray>this.myForm.controls['formArray'];
        arrayControl.removeAt(index);
    }
    onSubmit(): void {
        console.log(this.myForm.value);
        // Your form value is outputted as a JavaScript object.
        // Parse it as JSON or take the values necessary to use as you like
    }
}

Código de subcomponente: (uno para cada nuevo campo de entrada, para mantener las cosas limpias)

import { Component, Input } from '@angular/core';
import { FormGroup } from '@angular/forms';

@Component({
    selector: 'my-form-sub-component',
    templateUrl: './my-form-sub-component.html'
})
export class MyFormSubComponent {
    @Input() myForm: FormGroup; // This component is passed a FormGroup from the base component template
}

HTML del componente base

<form [formGroup]="myForm" (ngSubmit)="onSubmit()" novalidate>
    <label>Appears Once:</label>
    <input type="text" formControlName="appearsOnce" />

    <div formArrayName="formArray">
        <div *ngFor="let control of myForm.controls['formArray'].controls; let i = index">
            <button type="button" (click)="delInput(i)">Delete</button>
            <my-form-sub-component [myForm]="myForm.controls.formArray.controls[i]"></my-form-sub-component>
        </div>
    </div>
    <button type="button" (click)="addInput()">Add</button>
    <button type="submit" [disabled]="!myForm.valid">Save</button>
</form>

HTML de subcomponente

<div [formGroup]="form">
    <label>Property One: </label>
    <input type="text" formControlName="propertyOne"/>

    <label >Property Two: </label>
    <input type="number" formControlName="propertyTwo"/>
</div>

En el código anterior, básicamente tengo un componente que representa la base del formulario y luego cada subcomponente administra el suyo. FormGroup instancia dentro de la FormArray situado dentro de la base FormGroup. La plantilla base pasa a lo largo del subgrupo al subcomponente y luego puede manejar la validación de todo el formulario de forma dinámica.

Además, esto hace que sea trivial reordenar los componentes insertándolos estratégicamente y eliminándolos del formulario. Funciona con (aparentemente) cualquier cantidad de entradas, ya que no entran en conflicto con los nombres (una gran desventaja de los formularios basados ​​en plantillas, hasta donde yo sé) y aún conserva la validación prácticamente automática. El único “inconveniente” de este enfoque es que, además de escribir un poco más de código, debe volver a aprender cómo funcionan los formularios. Sin embargo, esto abrirá posibilidades para formas mucho más grandes y dinámicas a medida que avanza.

Si tiene alguna pregunta o desea señalar algunos errores, continúe. Acabo de escribir el código anterior basado en algo que hice yo mismo la semana pasada con los nombres cambiados y otros misceláneos. propiedades excluidas, pero debería ser sencillo. La única diferencia importante entre el código anterior y el mío es que moví toda la creación de formularios a un servicio separado que se llama desde el componente, por lo que es un poco menos complicado.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags : /

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *