File

src/app/GN2CommonModule/form/dynamic-form-generator/dynamic-form-generator.component.ts

Description

Ce composant permet de créer dynamiquement des formulaire à partir
de paramètres passés sous forme d'un tableau d'objets.

Metadata

selector pnx-dynamic-form-generator
styleUrls dynamic-form-generator.component.scss
templateUrl dynamic-form-generator.component.html

Inputs

autoGenerated

Est-ce que

  • (autoGenerated == true) : tous les champs du formulaire sont présents
  • (autoGenerated == false) : ou bien le formulaire doit être controlé par un champ select
    pour afficher/masquer les champs du formulaire.
    Par défault (autoGenerated == false) le formulaire est controlé par un champ select.

Default value: false

defaults

Dictionnaire qui permet

  • de donner des valeurs par défaut au formulaire
  • et d'afficher les champs concernés
    (dans le cas où l'input autoGenerated est égal à false)
    Exemple:
    defaults = {
    id_nomenclature_observation_status: [84],
    id_nomenclature_valid_status = [458,315,320,316,319,317]
    }

Type: any

formsDefinition

Type: any[]

myFormGroup

Type: any

selectLabel

Type: string

Outputs

change $event type: EventEmitter
myFormGroupChange $event type: EventEmitter

Constructor

constructor(_dynformService: DynamicFormService)

Methods

initDynamicForm
initDynamicForm()
Returns: void
hasValueChanged
hasValueChanged(newValue: any)

on teste s'il y a un changement entre this.myFormGroup.value et valueSaved;

Returns: void
setForms
setForms()
Returns: void
onFormsChange
onFormsChange(newValue: any)
Returns: void
removeFormControl
removeFormControl(i: any)
Returns: void
addFormControl
addFormControl(formDef: any)
Returns: void

Properties

Public formControlBuilded
formControlBuilded: boolean
Default value: false
Public formsDisplayed
formsDisplayed: any[]
Public formsHidden
formsHidden: any[]
Public formsSelected
formsSelected: any[]
Public oldValue
oldValue: {}
Public selectControl
selectControl: any
Public update
update: any
import { Component, OnInit, OnChanges, Input, Output, EventEmitter } from '@angular/core';
import { UntypedFormGroup, UntypedFormControl } from '@angular/forms';
import { DynamicFormService } from './dynamic-form.service';
import * as equal from 'fast-deep-equal/es6';
import { filter } from 'rxjs/operators';

/**
 * Ce composant permet de créer dynamiquement des formulaire à partir
 * de paramètres passés sous forme d'un tableau d'objets.
 */
@Component({
  selector: 'pnx-dynamic-form-generator',
  templateUrl: './dynamic-form-generator.component.html',
  styleUrls: ['./dynamic-form-generator.component.scss'],
})
export class GenericFormGeneratorComponent implements OnInit, OnChanges {
  public formControlBuilded = false;
  public selectControl = new UntypedFormControl();

  public formsHidden = [];
  public formsDisplayed = [];

  public oldValue = {};
  public update;

  @Input() myFormGroup: UntypedFormGroup;
  @Output() myFormGroupChange = new EventEmitter<any>();

  @Input() formsDefinition: Array<any>;
  @Input() selectLabel: string;

  @Output() change = new EventEmitter<any>();

  /**
   * Est-ce que
   * - (autoGenerated == true) : tous les champs du formulaire sont présents
   * - (autoGenerated == false) : ou bien le formulaire doit être controlé par un champ select
   *   pour afficher/masquer les champs du formulaire.
   * Par défault (autoGenerated == false) le formulaire est controlé par un champ select.
   */
  @Input() autoGenerated = false;

  /**
   * Dictionnaire qui permet
   * - de donner des valeurs par défaut au formulaire
   * - et d'afficher les champs concernés
   *   (dans le cas où l'input autoGenerated est égal à false)
   * Exemple:
   *   defaults = {
   *     id_nomenclature_observation_status: [84],
   *     id_nomenclature_valid_status = [458,315,320,316,319,317]
   *   }
   */
  @Input() defaults: any;

  public formsSelected = [];

  constructor(private _dynformService: DynamicFormService) {}

  ngOnInit() {
    this.formsDefinition = this.formsDefinition || [];
    this.initDynamicForm();
    this.myFormGroup.valueChanges.subscribe((values) => {
      this.onFormsChange(values);
    });
  }

  ngOnChanges(changes) {
    // on formdef changes, regenerate the form and UI
    // Do not load the form at first change: done by ngOnInit which wait for the component to be ready
    if (
      changes.formsDefinition &&
      !changes.formsDefinition.firstChange &&
      changes.formsDefinition.currentValue
    ) {
      for (const controlName in this.myFormGroup.controls) {
        this.myFormGroup.removeControl(controlName);
      }
      this.initDynamicForm();
    }
  }

  initDynamicForm() {
    if (this.autoGenerated) {
      if (!this.myFormGroup) {
        this.myFormGroup = this._dynformService.initFormGroup();
      }

      // HACK: formeSelect = formDefinition en mode autoGenerated = true
      // (on affiche tous les champs sans les filtrer au préalable)
      this.formsSelected = this.formsDefinition;
      this.formsDefinition.forEach((formDef) => {
        if (formDef.type_widget) {
          this._dynformService.addNewControl(formDef, this.myFormGroup);
        }
        // attribution de la valeur par defaut
        if (this.defaults && this.defaults[formDef.atribute_name] != null) {
          const value = {};
          value[formDef.atribute_name] = this.defaults[formDef.atribute_name];
          this.myFormGroup.patchValue(value);
        }
      });
    } else {
      // dans le cas non auto-généré
      // s'il y a des valeurs par defaut
      //   -on affiche les champs concernés
      //   - et on donne la valeur par défaut
      for (const [defaultKey, defaultValue] of Object.entries(this.defaults || {})) {
        const formDef = this.formsDefinition.find((formDef) => formDef.attribut_name == defaultKey);
        if (!formDef) {
          continue;
        }
        this.addFormControl(formDef);
        const value = {};
        value[defaultKey] = defaultValue;
        this.myFormGroup.patchValue(value);
      }

      this.selectControl.valueChanges
        .pipe(filter((value) => value !== null))
        .subscribe((formDef) => {
          this.addFormControl(formDef);
        });
      this.formsDefinition.sort((a, b) => {
        return a.attribut_label.localeCompare(b.attribut_label);
      });
    }
    this.setForms();
    this.formControlBuilded = true;
    this.myFormGroupChange.emit(this.myFormGroup);
  }

  /**
   * on teste s'il y a un changement entre this.myFormGroup.value et valueSaved;
   */
  hasValueChanged(newValue) {
    return !equal(newValue, this.oldValue);
  }

  setForms() {
    this.formsDisplayed = this.formsSelected.filter(
      (formDef) => !this._dynformService.getFormDefValue(formDef, 'hidden', this.myFormGroup.value)
    );
    this.formsHidden = this.formsSelected.filter((formDef) =>
      this._dynformService.getFormDefValue(formDef, 'hidden', this.myFormGroup.value)
    );
  }

  onFormsChange(newValue) {
    if (this.hasValueChanged(newValue)) {
      // mise à jour des formulaires affichés / cachés
      this.setForms();

      // pour dire aux formulaires qu'il y a un changement;

      // fy ExpressionChangedAfterItHasBeenCheckedError
      setTimeout(() => {
        this.update = true;
      });

      setTimeout(() => {
        this.update = false;
      }, 500);

      this.change.emit(newValue);
      this.oldValue = { ...newValue };
    }
  }

  removeFormControl(i) {
    const formDef = this.formsSelected[i];
    this.formsSelected.splice(i, 1);
    this.formsDefinition.push(formDef);
    this.myFormGroup.removeControl(formDef.attribut_name);
    this.selectControl.setValue(null);
  }

  addFormControl(formDef) {
    this.formsSelected.push(formDef);
    this.formsDefinition = this.formsDefinition.filter((form) => {
      return form.attribut_name !== formDef.attribut_name;
    });
    this._dynformService.addNewControl(formDef, this.myFormGroup);
    // pour être sûr que les composants (displayed et hidden) soient bien mis à jour)
    this.setForms();
  }
}

results matching ""

    No results matching ""