The AOC Framework
github logodiscord logo

FRONTEND

<aoc-from> #

Este componente se usa para mostrar un formulario, es decir, para la creación y edición de modelos.

A nivel visual, los formularios se colocan dentro de ventanas, aunque esto es transparente para el programador.

Inputs #

Nombre Tipo Descripción
modelConfig AocModelConfig La instancia model-config que se usará internamente
formGroup FormGroup El FormGroup asociado al formulario
restOptions AocRestOptions Las opciones de carga para la api rest
saveButtonWithTypeSubmit boolean (default: false) Útil para formularios que quieres enviar al pulsar la tecla enter
newModelTitle string, Observable, Promise, function Proveer el título de la ventana del formulario al crear un nuevo modelo
editModelTitle string, Observable, Promise, function Proveer el título de la ventana del formulario al editar un nuevo modelo
saveModel 'persist' o 'persistWithTask' El modo persist no cierra la ventana hasta que el servidor ha respondido (por defecto), el modo persistWithTask realiza la acción en segundo plano para evitar timeouts en la llamada xhr

Outputs #

Nombre Tipo Descripción
aocDynFormGroup AocDynFormGroup Emite la configuración de formulario dinámica

Nota: AocDynFormGroup es una configuración que permite establecer valores o estados a un control en un momento dado, incluso crear el control si es necesario. Al abrir una ventana de formulario, se le puede enviar dicha información, como por ejemplo sería establecer un valor para una dependencia (de otro modelo).

Ejemplo #

Un formulario con un campo de texto (Name). El componente aoc-form debe estructurarse de la siguiente forma. El template body y los elementos aoc-ui-form-page y aoc-ui-form-row son necesarios.

<aoc-form [formGroup]="formGroup" [modelConfig]="modelConfig">
  <ng-template aocFormTemplate="body">
    <aoc-ui-form-page>
      <aoc-ui-form-row>
        <input aocUiInputText aocUiFormField="Name" [formControlName]="StoreClass.field.NAME">
      </aoc-ui-form-row>
    </aoc-ui-form-page>
  </ng-template>
</aoc-form>

El atributo StoreClass hace referencia al modelo Store y se usa para para enlazar los campos del modelo con el formulario a través del formControlName.

export default class StoreFormComponent {
  protected StoreClass = Store;
  protected modelConfig = inject(StoreModelConfig);
  protected formGroup = new FormGroup<AocFormGroupType<Store>>({
    name: new FormControl(null, Validators.required)
  });
}

Vea el ejemplo completo en quest-client/src/app/features/schemas/items/store/store-form.component.ts

Ejemplo avanzado #

Este es un ejemplo de un formulario con pestañas (tiene 3 pestañas: Data, Contact, Files), con agrupaciones de campos, subformularios y subcomponentes.

<aoc-form [modelConfig]="modelConfig" [formGroup]="formGroup" [restOptions]="restOptions">
  <ng-template aocFormTemplate="body">
    <aoc-ui-tab-panel>
      <aoc-ui-tab-panel-content header="Data">
        <aoc-ui-form-page>
          <aoc-ui-form-row>
            <input aocUiInputText aocUiFormField="Code" [formControlName]="CustomerClass.field.CODE" placeholder="Autogenerated on server if empty...">
            <app-language-autocomplete aocUiFormField="Language" [formControlName]="CustomerClass.entity.LANGUAGE"></app-language-autocomplete>
            <app-gender-autocomplete aocUiFormField="Gender" [formControlName]="CustomerClass.entity.GENDER"></app-gender-autocomplete>
          </aoc-ui-form-row>
          <app-legal-data-template-subform [formGroupName]="CustomerClass.embedded.LEGAL_DATA_TEMPLATE"></app-legal-data-template-subform>
          <aoc-ui-form-row>
            <input aocUiInputText aocUiFormField="Trade name" [span]="18" [formControlName]="CustomerClass.field.TRADE_NAME" placeholder="Just for companies, not mandatory...">
            <aoc-ui-datetime-picker aocUiFormField="Birthdate" [formControlName]="CustomerClass.field.BIRTHDATE" mode="date" placeholder="mm/dd/y"></aoc-ui-datetime-picker>
          </aoc-ui-form-row>
          <app-address-template-subform [formGroupName]="CustomerClass.embedded.ADDRESS_TEMPLATE"></app-address-template-subform>
        </aoc-ui-form-page>
      </aoc-ui-tab-panel-content>
      <aoc-ui-tab-panel-content header="Contact">
        <aoc-ui-form-page>
          <aoc-ui-form-fieldset title="Main Contact Info">
            <app-contact-template-subform></app-contact-template-subform>
          </aoc-ui-form-fieldset>
          <aoc-ui-form-row aocUiFormRowHeight="stretch">
            <app-contact-grid-field aocUiFormField="Additional Contacts" [formControlName]="CustomerClass.collection.CONTACT"></app-contact-grid-field>
          </aoc-ui-form-row>
        </aoc-ui-form-page>
      </aoc-ui-tab-panel-content>
      <aoc-ui-tab-panel-content header="Files">
        <aoc-ui-form-page>
          <aoc-ui-form-row aocUiFormRowHeight="stretch">
            <app-file-grid-field
              aocUiFormField="Customer files (documents, contracts...)"
              [formControlName]="CustomerClass.collection.FILE"
              [fileParentClass]="CustomerClass"
              fileDirectory="Customers"
            ></app-file-grid-field>
          </aoc-ui-form-row>
        </aoc-ui-form-page>
      </aoc-ui-tab-panel-content>
    </aoc-ui-tab-panel>
  </ng-template>
</aoc-form>

En la definición del formGroup tenemos ejemplos de validadores, campos embedidos (subobjeto), campos inline (campos al mismo nivel), y colecciones (relaciones en PostgreSQL). Tanto los campos embedidos como los campos inline podrían expresarse como herencias en PostgreSQL.

Las restOptions indican que se deben cargar ciertas relaciones para que el formulario pueda mostrar los datos correctamente (por ejemplo, el editar).

this.formGroup = new FormGroup<AocFormGroupType<Customer>>({
  code: new FormControl(null, AocUiValidators.positiveNumber(0)),
  trade_name: new FormControl(null),
  birthdate: new FormControl(null),
  gender: new FormControl(this.questDefaultsService.gender),
  language: new FormControl(this.questDefaultsService.language, Validators.required),
  legalDataTemplate: this.questUtilsService.addControlsForLegalDataTemplate(), // Embedded
  addressTemplate: this.questUtilsService.addControlsForAddressTemplate(), // Embedded
  contactCollection: new FormControl([]),
  fileCollection: new FormControl([])
});

// Inline
this.questUtilsService.addControlsForContactTemplate(this.formGroup);

this.restOptions = {
  populate: {
    language: true,
    gender: true,
    contactCollection: true,
    fileCollection: true
  }
}

Ejemplo completo en quest-client/src/app/features/schemas/customers/customer/customer-form.component.ts

API #

Definición completa en la API.

<aoc-subform> #

Este componente se utiliza para subformularios (formularios dentro de formularios).

En el ejemplo avanzado, se usaría en <app-legal-data-template-subform>.

El template recibe el formGroup por contexto automáticamente y, en este caso, lo asignamos a la directiva formGroup de la nueva row en cuestión aoc-ui-form-row que añadimos al formulario padre.

<aoc-subform>
  <ng-template let-formGroup>
    <aoc-ui-form-row [formGroup]="formGroup">
      <input aocUiInputText aocUiFormField="Legal name" [formControlName]="LegalDataTemplateClass.field.LEGAL_NAME">
      <input [span]="6" aocUiInputText aocUiFormField="Document number" [formControlName]="LegalDataTemplateClass.field.DOCUMENT_NUMBER">
      <app-identity-document-type-autocomplete
        [span]="6"
        aocUiFormField="Identity document type"
        [formControlName]="LegalDataTemplateClass.entity.IDENTITY_DOCUMENT_TYPE"
      ></app-identity-document-type-autocomplete>
    </aoc-ui-form-row>
  </ng-template>
</aoc-subform>

El modelo LegalDataTemplate es un AocEmbeddedModel que no es más que un modelo normal con algunas simplificaciones (echa un ojo a mikro-orm.

protected LegalDataTemplateClass = LegalDataTemplate;

API #

Definición completa en la API.

AocFormController #

En los formularios siempre hay que proveer AocFormController. Esta clase funciona como herramienta de control del ciclo de vida de los formularios y nos permite engancharnos a hooks, entre otras funcionalidades.

Además, siempre podremos inyectarla también en componentes que estén dentro de la misma jerarquía de nuestro formulario padre.

providers: [ AocFormController ]

Por ejemplo, recargamos el navegador cuando hemos pulsado en el botón Guardar de un formulario y se ha guardado correctamente el modelo. El modelo se recibe como parámetro.

this.aocFormController.addAfterSaveAction(_ => {
  window.location.reload();
});

API #

Definición completa en la API.

Por favor, busque en Issues y Discussions en Github para más información

© 2024 Atlantis of Code. All rights reserved.
All trademarks are the property of their respective owners.