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));
});
}
}
2 respuestas
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: ''
})
});
Espero que ayude y feliz codificación!
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.
Preguntas relacionadas
Nuevas preguntas
angular
Preguntas sobre Angular (que no debe confundirse con AngularJS), el marco web de Google. Use esta etiqueta para preguntas angulares que no son específicas de una versión individual. Para el marco web anterior de AngularJS (1.x), use la etiqueta angularjs.