<aoc-from>
#This component is used to display a form, i.e., for the creation and editing of models.
Visually, forms are placed within windows, although this is transparent to the programmer.
Name | Type | Description |
---|---|---|
modelConfig | AocModelConfig | The model-config instance that will be used internally |
formGroup | FormGroup | The FormGroup associated with the form |
restOptions | AocRestOptions | Loading options for the REST API |
saveButtonWithTypeSubmit | boolean (default: false) | Useful for forms that you want to submit by pressing the enter key |
newModelTitle | string, Observable, Promise, function | Provide the window title of the form when creating a new model |
editModelTitle | string, Observable, Promise, function | Provide the window title of the form when editing a new model |
saveModel | 'persist' or 'persistWithTask' | The persist mode does not close the window until the server has responded (by default), persistWithTask runs the action in the background to avoid timeouts on the xhr call |
Name | Type | Description |
---|---|---|
aocDynFormGroup | AocDynFormGroup | Emits the dynamic form configuration |
Note: AocDynFormGroup is a configuration that allows setting values or states to a control at a given moment, even creating the control if necessary. When opening a form window, such information can be sent, such as setting a value for a dependency (from another model).
A form with a text field (Name). The aoc-form
component should be structured as follows.
The body
template and the aoc-ui-form-page
and aoc-ui-form-row
elements are necessary.
<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>
The StoreClass
attribute refers to the Store
model and is used to link the model fields to the form through the formControlName
.
export default class StoreFormComponent {
protected StoreClass = Store;
protected modelConfig = inject(StoreModelConfig);
protected formGroup = new FormGroup<AocFormGroupType<Store>>({
name: new FormControl(null, Validators.required)
});
}
See the full example at quest-client/src/app/features/schemas/items/store/store-form.component.ts
This is an example of a tabbed form (it has 3 tabs: Data, Contact, Files), with field groupings, subforms, and subcomponents.
<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>
In the definition of the formGroup
we have examples of validators, embedded fields (subobject), inline fields (fields at the same level), and collections (relations in PostgreSQL).
Both embedded and inline fields could be expressed as inheritances in PostgreSQL.
The restOptions
indicate that certain relations need to be loaded for the form to display data correctly (for example, when editing).
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
}
}
Complete example at quest-client/src/app/features/schemas/customers/customer/customer-form.component.ts
Full definition in the API.
<aoc-subform>
#This component is used for subforms (forms within forms).
In the advanced example, it would be used in <app-legal-data-template-subform>
.
The template automatically receives the formGroup
by context, and in this case, we assign it to the formGroup
directive of
the new row in question aoc-ui-form-row
that we add to the parent form.
<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>
The LegalDataTemplate
model is an AocEmbeddedModel
which is just a normal model with some simplifications (take a look at mikro-orm.
protected LegalDataTemplateClass = LegalDataTemplate;
Full definition in the API.
aocformcontroller
#In forms, always provide AocFormController
. This class functions as a tool
to control the lifecycle of forms and allows us to hook into hooks, among other functionalities.
Additionally, it can also be injected into components within the same hierarchy as our parent form.
providers: [ AocFormController ]
For example, we reload the browser when we have clicked on the Save button of a form and the model has been saved successfully. The model is received as a parameter.
this.aocFormController.addAfterSaveAction(_ => {
window.location.reload();
});
Full definition in the API.
Please note, browse Issues and Discussions in Github for more information