Formularios reactivos con plantillas recursivas dinámicas

8

Aquí está mi problema.

Ejemplo en línea del problema

Tengo un JSON dinámico que necesito convertir a un formulario. Entonces, utilicé formas reactivas y al revisar todas las propiedades del JSON creo un FormGroup o FormControl, de esta manera:

sampleJson ={prop1:"value1", prop2: "value2",...}

...

  myForm: FormGroup;
  myKeys=[];
    ...

  ngOnInit() {
    this.myForm = this.getFormGroupControls(this.sampleJson, this.myKeys);

  }

getFormGroupControls(json:any,keys): FormGroup{
    let controls = {};
    let value = {};

    for (let key in json) {
      if (json.hasOwnProperty(key)) {

        value = json[key];
        if (value instanceof Object && value.constructor === Object) {

          keys.push({"key":key,children:[]});
          controls[key] = this.getFormGroupControls(value,keys[keys.length-1].children);
        } else {

          keys.push({"key":key,children:[]});
          controls[key] = new FormControl(value);

        }
      }
    }

    return new FormGroup(controls);
  }

Después de hacerlo, uso plantillas recursivas para construir el formulario, si no uso plantillas recursivas, hago que el formulario funcione. Sin embargo, con las plantillas recursivas obtengo errores:

<form [formGroup]="myForm">

  <div class="form-group">


    <ng-template #nodeTemplateRef let-node>

      <div class="node">
        <div  *ngIf="node.children.length">
          {{"section [formGroupName]="}} {{ getNodeKey(node) }}
          <section style="display:block;margin:20px;border:solid 1px blue;padding-bottom: 5px;"
            [formGroupName]="getNodeKey(node)" >
            <h1>{{ node.key }}</h1>
            <ng-template
              ngFor
              [ngForOf]="node.children"
              [ngForTemplate]="nodeTemplateRef">
            </ng-template>
          </section>
          {{"end of section"}}
        </div>
        <div  *ngIf="!node.children.length">
          <label [for]="node.key">{{node.key}}</label>&nbsp;
          <input  type="text" [id]="node.key"
                  class="form-control">
        </div>
      </div>

    </ng-template>

    <ng-template *ngFor="let myKey of myKeys"
                 [ngTemplateOutlet]="nodeTemplateRef"
                 [ngTemplateOutletContext]="{ $implicit: myKey   }">
    </ng-template>

  </div>

FormerComponent.html: 25 ERROR Error: no se puede encontrar el control con el nombre: 'carretera'

Eso corresponde a esta muestra JSON:

"address": {
        "town": "townington",
        "county": "Shireshire",

        "road": {
          "number": "1",
          "street": "the street"
        }

Se está mostrando, así que sé que los elementos están ahí. ¿Qué me estoy perdiendo?

Dalorzo
fuente
Creo que [formGroupName]="road"no es consciente de que está anidado bajo el grupo de addressformularios. Está buscando un grupo de formularios nombrado roaddirectamente debajo de la raíz [formGroup]="myForm". Si anida un grupo de roadformularios directamente debajo myForm, verá que el error ya no aparece.
Alex K
Reemplazar formGroupNamepor formGrouptodas partes podría solucionar el problema. Pero necesitará una forma de obtener la FormGroupinstancia correcta para cada grupo anidado.
Alex K
que crea este otro error> No se puede crear la propiedad 'validador' en la cadena 'nombre'
Dalorzo
¿El json dinámico siempre devolverá un conjunto conocido? eso podría cambiar pero podemos ser conscientes de ellos y tener algo seguro?
maxime1992
Supongo que lo que estoy preguntando es: ¿es realmente dinámico o es solo oneOfde un conjunto conocido de posibles entradas como name,personal , addressetc.
maxime1992

Respuestas:

2

O si aún desea la jerarquía de grupos / controles de formulario, puede usar las directivas formGroup y formControl pasándolas de forma recursiva (en lugar de formGroupName y formControlName)

Enlace Stackblits

NB: el mismo problema aquí: Recursive ReactiveForm no puede encontrar formGroups dentro de la plantilla

Neji Sghair
fuente
1
este +1 es una solución impresionante ..
Dalorzo
Este terminó funcionando mucho mejor y requirió menos cambios en mi objetivo original. Es por eso que le doy la respuesta, ya que creo que es más preciso
Dalorzo
9

El problema con su código actual parece ser que ng-template parent es el componente de su aplicación, por lo que no tiene en cuenta otros formGroupNames en las plantillas principales que definió y siempre busca en el FormGroup raíz.

También parece que el nombre completo del grupo / nombre de control no es compatible con las plantillas (por ejemplo, no se puede usar formGroupName="address.road")

Si necesita por alguna razón formGroups, puede pasarlos en contexto a las plantillas. O puede dirigirse a formControls directamente:

  • eliminar todo formGroupNamede la plantilla
  • store fullPath: keys.push({"key":key,children:[], fullKey: parent ? parent.fullKey + '.' + key: key});(también puede almacenar la FormControlinstancia en sí).
  • y úsalo: <input type="text" [formControl]="myForm.get(node.fullKey)"

Ejemplo de Stackblitz

Petr Averyanov
fuente