Estoy tratando de construir una tabla de datos compatible con FormGroup y FormArray. Pasaré los detalles del encabezado y las filas a este componente con el grupo parentForm.

He creado un pequeño botón Agregar, al hacer clic en él, agregaré nuevos elementos de forma dinámica. En este caso, la interfaz de usuario se está actualizando bien, pero si imprimo formGroup.value (), solo obtengo el valor inicial pasado. No el formControl actualizado. No estoy seguro de lo que me estoy perdiendo.

export class FormTableComponent implements OnChanges {
    @Input() headers: Array<string>;
    @Input() rows: Array<any>;
    @Input() parentFG: FormGroup;
    @Input() entriesName: string;

    get entries(): FormArray {
        return <FormArray>this.parentFG.get(this.entriesName);
    }

    constructor(private fb: FormBuilder, private cd: ChangeDetectorRef) {}

    ngOnChanges() {
        this.createFormControls();
    }

    createFormControls() {
        this.parentFG.controls[this.entriesName] = this.fb.array([]);
        this.rows.forEach(row => {
            this.entries.controls.push(this.fb.group(row));
        });
    }
}

DEMO

4
Manoj 16 feb. 2018 a las 22:42

2 respuestas

La mejor respuesta

Tiene un par de problemas: 1. envía una nueva fila a los controles de FormArray que no sean FormArray.

this.entries.controls.push(this.fb.group(row));

Debe ser

this.entries.push(this.fb.group(row));

2. no cree un nuevo FormArray cada vez y vuelva a cargar cada fila cuando invoque createFormControls(), puede acceder a él mediante su método get entries()

Solución 1:

Verifique la longitud de entries, si es 0, inicialícela con rows; de lo contrario, simplemente inserte la última fila en el FormArray existente.

createFormControls() {
        const keys = Object.keys(this.entries.value);
        if( keys.length === 0) {
          this.rows.forEach(row => {
              this.entries.push(this.fb.group(row));
          });
        } else {
          const row = this.rows[this.rows.length - 1];
          this.entries.push(this.fb.group(row));
        }
    }

Solución 2:

Personalmente, prefiero poner createFormArray() y appendTo() o popFrom() en el componente principal. Es limpio y fácil de leer. No necesitamos ChangeDetectionRef en este caso.

Moví createFormControls() del componente form-table al componente dummy y le cambié el nombre a createFormArray() y cambié addNewRow() un poco, ahora todo funciona correctamente

// create FormArray once
createFormArray() {
    const elements: any[] =[];

    this.rows.forEach(row => {
        elements.push(this.fb.group(row));
    });
    return this.fb.array(elements);
}

addNewRow() {
  const newRow =    {
            name: 'NAFFD',
            age: 12,
            place: 'TN'
        };

    this.rows.push(newRow);  // update rows

    const persons =  this.dummyForm.get('persons') as FormArray;
    persons.push(this.fb.group(newRow));  // update FormArray
}

Al inicializar su formulario ficticio, haga lo siguiente:

   this.dummyForm = this.fb.group({
        persons: this.createFormArray(),
        store: this.fb.group({
            branch: '',
            code: ''
        })
    });

enter image description here

Espero que ayude y feliz codificación!

5
Haifeng Zhang 16 feb. 2018 a las 21:02

Este es un error común sobre ngOnChanges. ngOnChanges funciona mejor con tipos primitivos, porque se pasan por valor.

Los objetos y matrices en Javascript se pasan por referencia. Dicho esto, ngOnChanges está buscando el valor de la entrada proporcionada para cambiar. En este caso, la referencia a su matriz es la entrada proporcionada , no los valores dentro de la matriz. Entonces, a menos que esté pasando una nueva matriz al componente, ngOnChanges no se activará, por lo que no volverá a renderizar su formulario.

Una solución rápida y sucia podría ser volver a crear una instancia del objeto / matriz cada vez que lo actualice en el lado principal.

this.rows = Object.assign([], newRows);

Esto crearía una matriz completamente nueva, que a su vez debería cambiar la referencia y finalmente obligar a ngOnChanges a disparar sobre el niño.

Alternativamente, podría convertir de alguna manera sus filas en un Observable y suscribirse a él dentro del niño. Personalmente, los Observables son una forma mucho más limpia de lidiar con la Detección de cambios fuera de los Tipos primitivos. Aquí hay una excelente reseña de los documentos sobre la comunicación entre padres e hijos a través de un servicio.

0
joshrathke 16 feb. 2018 a las 20:00