tuain-ng-forms-lib 17.3.7 → 17.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +280 -335
  2. package/esm2022/lib/classes/forms/action.mjs +3 -3
  3. package/esm2022/lib/classes/forms/element.mjs +2 -2
  4. package/esm2022/lib/classes/forms/field.mjs +2 -5
  5. package/esm2022/lib/classes/forms/form.mjs +4 -6
  6. package/esm2022/lib/classes/forms/piece-propagate.mjs +1 -1
  7. package/esm2022/lib/classes/forms/piece.mjs +2 -2
  8. package/esm2022/lib/classes/forms/section.mjs +2 -2
  9. package/esm2022/lib/classes/forms/subsection.mjs +1 -1
  10. package/esm2022/lib/classes/forms/table/action.mjs +1 -1
  11. package/esm2022/lib/classes/forms/table/column.mjs +1 -1
  12. package/esm2022/lib/classes/forms/table/row-data.mjs +3 -5
  13. package/esm2022/lib/classes/forms/table/table.mjs +2 -2
  14. package/esm2022/lib/components/elements/layout/piece.component.mjs +3 -3
  15. package/esm2022/lib/components/elements/tables/table-record-action.component.mjs +1 -1
  16. package/esm2022/lib/components/elements/tables/table-record-field.component.mjs +1 -1
  17. package/esm2022/lib/components/forms/basic-form.mjs +23 -24
  18. package/esm2022/lib/interfaces/action.interface.mjs +2 -0
  19. package/esm2022/lib/interfaces/field.interface.mjs +2 -0
  20. package/esm2022/lib/interfaces/form-config.interface.mjs +1 -1
  21. package/esm2022/lib/interfaces/form.interface.mjs +2 -0
  22. package/esm2022/lib/interfaces/index.mjs +9 -1
  23. package/esm2022/lib/interfaces/piece.interface.mjs +2 -0
  24. package/esm2022/lib/interfaces/section.interface.mjs +2 -0
  25. package/esm2022/lib/interfaces/sse-live-connection.interface.mjs +2 -0
  26. package/esm2022/lib/interfaces/table.interface.mjs +2 -0
  27. package/esm2022/lib/services/file-manager.service.mjs +5 -5
  28. package/esm2022/lib/services/form-manager.service.mjs +5 -5
  29. package/esm2022/lib/services/icon-dictionary.service.mjs +1 -1
  30. package/esm2022/lib/services/sse-live-connection.service.mjs +165 -0
  31. package/esm2022/lib/tokens/sse-live-connection.token.mjs +7 -0
  32. package/esm2022/public-api.mjs +3 -1
  33. package/fesm2022/tuain-ng-forms-lib.mjs +213 -53
  34. package/fesm2022/tuain-ng-forms-lib.mjs.map +1 -1
  35. package/lib/classes/forms/action.d.ts +3 -2
  36. package/lib/classes/forms/element.d.ts +2 -1
  37. package/lib/classes/forms/field.d.ts +5 -4
  38. package/lib/classes/forms/form.d.ts +4 -2
  39. package/lib/classes/forms/piece-propagate.d.ts +2 -1
  40. package/lib/classes/forms/piece.d.ts +4 -3
  41. package/lib/classes/forms/section.d.ts +3 -2
  42. package/lib/classes/forms/subsection.d.ts +2 -1
  43. package/lib/classes/forms/table/action.d.ts +2 -1
  44. package/lib/classes/forms/table/column.d.ts +2 -1
  45. package/lib/classes/forms/table/row-data.d.ts +3 -2
  46. package/lib/classes/forms/table/table.d.ts +3 -1
  47. package/lib/components/elements/layout/piece.component.d.ts +2 -2
  48. package/lib/components/forms/basic-form.d.ts +4 -4
  49. package/lib/interfaces/action.interface.d.ts +23 -0
  50. package/lib/interfaces/field.interface.d.ts +70 -0
  51. package/lib/interfaces/form-config.interface.d.ts +24 -16
  52. package/lib/interfaces/form.interface.d.ts +106 -0
  53. package/lib/interfaces/index.d.ts +7 -0
  54. package/lib/interfaces/piece.interface.d.ts +67 -0
  55. package/lib/interfaces/section.interface.d.ts +56 -0
  56. package/lib/interfaces/sse-live-connection.interface.d.ts +59 -0
  57. package/lib/interfaces/table.interface.d.ts +139 -0
  58. package/lib/services/file-manager.service.d.ts +4 -4
  59. package/lib/services/form-manager.service.d.ts +3 -3
  60. package/lib/services/icon-dictionary.service.d.ts +1 -1
  61. package/lib/services/sse-live-connection.service.d.ts +48 -0
  62. package/lib/tokens/sse-live-connection.token.d.ts +7 -0
  63. package/package.json +2 -1
  64. package/public-api.d.ts +2 -0
package/README.md CHANGED
@@ -1,411 +1,356 @@
1
+ # tuain-ng-forms-lib
1
2
 
2
- # Tuain-ng-forms-lib
3
+ UI-agnostic core of the Tuain platform's **dynamic forms** framework for Angular 17+.
3
4
 
4
- Angular library to support Tuain Framework Forms operation.
5
+ It lets you build form-driven applications by rendering complete forms —fields, actions, tables and sections— from **JSON definitions sent by the server**, using a **reactive** programming model: each form is a class that declares *how it reacts* to UI events through callbacks, while the library takes care of instantiating the model, keeping the view in sync and orchestrating backend communication.
5
6
 
6
- ## Installation
7
+ > This library provides the **domain model**, the **abstract base components** and the **services**. It does not impose a UI library: concrete widgets are supplied by UI packages (e.g. `tuain-ng-forms-ant` with ng-zorro, `tuain-ng-forms-ionic` with Ionic) or by the application itself, by extending the base components.
7
8
 
8
- Use the package manager npm to install the library in your Angular 9 application
9
+ ## Table of contents
9
10
 
10
- ```bash
11
- npm install tuain-ng-forms-lib
12
- ```
11
+ 1. [Purpose and architecture](#1-purpose-and-architecture)
12
+ 2. [Services](#2-services)
13
+ 3. [Forms API and the reactive approach](#3-forms-api-and-the-reactive-approach)
14
+ 4. [Form lifecycle](#4-form-lifecycle)
15
+ 5. [Form composition and element access](#5-form-composition-and-element-access)
16
+ 6. [Model objects vs. view components](#6-model-objects-vs-view-components)
17
+ 7. [Using the library in an Angular project](#7-using-the-library-in-an-angular-project)
13
18
 
14
- ## Usage
19
+ ---
15
20
 
16
- Import the library module in your own module, and include it in your imports and exports if you need to use it with your own components in other application modules.
21
+ ## 1. Purpose and architecture
17
22
 
18
- ```typescript
19
- import { TuainNgFormsLibModule } from 'tuain-ng-forms-lib';
20
-
21
- ...
22
- @NgModule({
23
- imports: [
24
- ...
25
- TuainNgFormsLibModule,
26
- ...,
27
- ],
28
- declarations: [
29
- ...
30
- ],
31
- exports: [
32
- ...
33
- TuainNgFormsLibModule,
34
- ...
35
- ],
36
- })
37
- ```
23
+ The goal is to **leverage the construction of form-based applications**: instead of hand-coding every screen, the server describes the form (fields, actions, tables, sections, states) as JSON and the library materializes it as a graph of live objects with reactive behavior. The application only writes the form's **business logic** (what to do when a field is validated, an action is executed, etc.).
38
24
 
39
- ## Public API
40
-
41
- Tuain-ng-forms-lib expose a series of components and services to provide base clases to build forms in
42
- Angular applications following the Tuain Platforms standard behavior. The elements exposed by the API
43
- are described below.
25
+ The architecture is organized in layers:
44
26
 
45
- | Element | Name |
46
- | ------ | ------ |
47
- | Component | ActionComponent |
48
- | Component | FieldComponent |
49
- | Component | PasswordComponent |
50
- | Component | ElementComponent |
51
- | Component | FormErrorComponent |
52
- | Component | FormHeaderComponent |
53
- | Component | SectionComponent |
54
- | Component | SubSectionComponent |
55
- | Component | LibTableFilterComponent |
56
- | Component | LibTablePagerComponent |
57
- | Component | LibTableRecordActionComponent |
58
- | Component | LibTableRecordFieldComponent |
59
- | Component | LibTableComponent |
60
- | Component | BasicFormComponent |
61
- | Service | LibFileManagementService |
62
- | Service | LibFormManagerService |
63
- | Service | IconDictionaryService |
27
+ ```
28
+ ┌──────────────────────────────────────────────────────────────────┐
29
+ │ PRESENTATION LAYER (concrete UI) │
30
+ │ tuain-ng-forms-ant (ng-zorro) · tuain-ng-forms-ionic (Ionic)·App │
31
+ │ Widgets that extend the base components and supply the template │
32
+ ├──────────────────────────────────────────────────────────────────┤
33
+ │ BASE COMPONENTS LAYER (abstract, standalone) │
34
+ │ FieldComponent · ActionComponent · LibTableComponent · … │
35
+ │ Sync model→view via signals; translate UI events │
36
+ ├──────────────────────────────────────────────────────────────────┤
37
+ │ MODEL LAYER (domain) │
38
+ │ FormStructureAndData · FieldDescriptor · FormAction · RecordTable │
39
+ │ Form structure + data + state (live objects) │
40
+ ├──────────────────────────────────────────────────────────────────┤
41
+ │ SERVICES LAYER │
42
+ │ FormManager · EventManager · FileManagement · IconResolver · SSE │
43
+ │ Server definition/actions, navigation, events, files │
44
+ └──────────────────────────────────────────────────────────────────┘
45
+
46
+
47
+ Angular 17+ · RxJS
48
+ ```
64
49
 
65
- ### Components
50
+ Model hierarchy (each level adds capabilities):
66
51
 
67
- These components can be customized in your own application using inheritance to define your
68
- own components that behaves like these base components but with your own custom templates.
52
+ ```
53
+ FormPiece visibility, enablement, states, customAttributes
54
+ └─ FormPiecePropagate reactive attribute propagation (BehaviorSubject)
55
+ ├─ FormElement elementType + setAttr() with propagation
56
+ │ ├─ FieldDescriptor field: value, validation, options, errors
57
+ │ ├─ FormAction action: backend, inProgress, restrictions
58
+ │ └─ RecordTable table: columns, records, paging, filters
59
+ ├─ RecordFormSection section (activation/navigation)
60
+ └─ RecordFormSubSection subsection (groups elements)
61
+
62
+ FormStructureAndData form container (fields + actions + tables + state)
63
+ └─ BasicFormComponent Angular component: lifecycle + callbacks + server
64
+ ```
69
65
 
70
- #### ActionComponent
66
+ Every public entity also has a **contract interface** (`IForm`, `IField`, `IAction`, `ITable`, `ITableColumn`, `ITableAction`, `ISection`, …) implemented by the classes; applications may type against the contracts instead of the concrete classes.
71
67
 
72
- This componet allows to create elements in a form to launch the execution of an action
73
- present in the form definition.
68
+ ---
74
69
 
75
- ##### Inputs
70
+ ## 2. Services
76
71
 
77
- This component allows to receive the following information
72
+ Services decouple the core from each application's specifics. They are provided via DI; some are **abstract by design** (the app implements them).
78
73
 
79
- | Input Name | Description |
80
- | --- | ----------- |
81
- | actionObjec | Defines the action object of the form |
82
- | currentMode | Defines the current state of the form in order to define if the element can be visible or actionable |
83
- | busy | Defines in the form is makinh an exclusive process that prevents the action execution |
84
- | relatedField | Describe the field object related with this action |
85
- | style | Define a style attribute for the action |
86
- | showLabel | Define if the action shows it's label
74
+ | Service / Token | Role | App implements? |
75
+ | --- | --- | --- |
76
+ | `LibFormManagerService` | Fetches the form definition (`getFormDefinition`), runs server actions (`execServerAction`), navigates between forms and manages the **navigation stack** (`openForm`, `backTo`, `stack`/`unstack`). | Yes (overrides the server/navigation methods) |
77
+ | `LibEventManagerService` | The app's **event bus** (Subject / BehaviorSubject / ReplaySubject) for communication between forms and components. | Instantiated with its set of events |
78
+ | `LibFileManagementService` | File handling (`openFile`, `saveFile`, `saveFileFromURL`, `printPdfFile`) per platform (web/mobile). | Yes |
79
+ | `BaseIconResolverService` + `ICON_RESOLVER` | **Extensible, multi-collection** icon resolution (each UI registers its collections). | Optional (extend/register) |
80
+ | `SseLiveConnectionService` + `SSE_LIVE_CONNECTION_CONFIG` | **Server→client** event channel over Server-Sent Events (native reconnection). All integration is provided through the config token. | Provides the config |
87
81
 
88
- ##### Methods
82
+ The core never assumes a concrete implementation: it defines the contract and the app satisfies it via `providers`.
89
83
 
90
- The action component has the following methods.
84
+ ---
91
85
 
92
- * activate: Allows to activate the action
93
- * icon: Returns the icon name of the action
94
- * isVisible: Informs if the action is visible in the form
86
+ ## 3. Forms API and the reactive approach
95
87
 
96
- #### FieldComponent
88
+ An application form is a **class that extends `BasicFormComponent`**. The central idea of the reactive approach is that **you don't program the flow imperatively**; instead you *declare how the form reacts to UI events*, registering callbacks that the library invokes at the right moment.
97
89
 
98
- ##### Inputs
90
+ UI components don't call business logic directly: they translate the UI event into a notification on the **model object**, and `BasicFormComponent` —subscribed to that object— fires the callbacks the app registered.
99
91
 
100
- This component allows to receive the following information
92
+ ```
93
+ User types in the input
94
+ │ (template) (ngModelChange)
95
+
96
+ FieldComponent.inputChanged()
97
+ ├─ updateObject() → field.setValue(...) (view → model)
98
+ └─ onChangeContent() → field.notifyEditionFinish()
99
+ │ emits on editionFinish (Subject)
100
+
101
+ BasicFormComponent.startFieldValidation(code)
102
+
103
+
104
+ callbacks registered with onFieldValidationStart(...)
105
+ │ (if ok and field.backend)
106
+
107
+ requestFormAction('VALIDATE') → updateFormWithServerData()
108
+
109
+ callbacks registered with onFieldValidationFinish(...)
110
+ ```
101
111
 
102
- | Input Name | Description |
103
- | --- | ----------- |
104
- | fieldObject | |
105
- | currentMode | |
112
+ Conversely, when the model changes (by code or by a server response) the view updates itself thanks to **reactive propagation**:
106
113
 
107
- ##### Methods
114
+ ```
115
+ field.setValue(x) → setAttr() → propagateAttribute('value', x)
116
+ │ │ _attributeChange.next(...) (BehaviorSubject)
117
+ │ ▼
118
+ │ FieldComponent (subscribed to field.attributeChange)
119
+ │ ▼
120
+ │ this.value.set(x) (signal) → template
121
+ ```
108
122
 
109
- The field component has the following methods.
123
+ ### Registering callbacks (how the form "reacts")
110
124
 
111
- * focus: Allows to focus on the native element of the field, usig the subclass method
112
- * onInputChange: Allows to link the change on the native element with the form manager behavior
113
- * onChangeContent: Allows to link the typing on the native element with the form manager behavior
114
- * onShowInfo: Allows to link the show infor request on the component custom template with the
115
- form event handler defined to support the respective action request.
116
- * numberInputValidation: Allows to use the number input validation to restrict the typing
125
+ Inside `start()` (or `preStart()`) the app registers the handlers:
117
126
 
118
- #### ElementComponent
127
+ ```typescript
128
+ // Actions
129
+ this.onActionStart('save', (action) => this.validateBeforeSaving()); // false cancels
130
+ this.onActionFinish('save', (action, result) => this.notifySaved());
119
131
 
120
- ##### Inputs
132
+ // Fields
133
+ this.onFieldValidationStart('email', (field) => this.preValidateEmail(field));
134
+ this.onFieldValidationFinish('email', (field) => this.afterValidateEmail(field));
135
+ this.onFieldInput('phone', (field) => this.formatWhileTyping(field));
121
136
 
122
- This component allows to receive the following information
137
+ // Tables
138
+ this.onTableActionStart('items', 'edit', (detail) => this.openEdition(detail));
139
+ this.onTableGetDataFinish('items', (detail, result) => this.afterPaging(detail));
123
140
 
124
- | Input Name | Description |
125
- | --- | ----------- |
126
- | element | |
127
- | formManager | |
141
+ // Sections and form
142
+ this.onSectionActivation('data', (section) => this.onEnterSection(section));
143
+ this.onFormChange((state) => this.onStateChanged(state));
128
144
 
129
- #### FormErrorComponent
145
+ // Server errors
146
+ this.onActionServerError((action) => this.showError());
147
+ ```
130
148
 
131
- ##### Inputs
149
+ Every callback that runs **before** the backend (`...Start`) can return `false` to **cancel** the flow. The `...Finish` ones run after the server part.
132
150
 
133
- This component allows to receive the following information
151
+ ---
134
152
 
135
- | Input Name | Description |
136
- | --- | ----------- |
137
- | errorTitle | |
138
- | errorMessage | |
139
- | errorType | |
153
+ ## 4. Form lifecycle
140
154
 
141
- #### FormHeaderComponent
155
+ ```
156
+ 1. Angular creates the form component (a BasicFormComponent subclass)
157
+ 2. ngOnInit() ─────────────► preStart() (config hook: formCode, route)
158
+ 3. The app calls formInit(params):
159
+ a. processInputParams() extracts token / subject / state from the stack
160
+ b. getFormDefinition(name) requests the JSON from the server (FormManager)
161
+ c. loadDefinition(json) ──────────► instantiates FieldDescriptor / FormAction /
162
+ RecordTable / RecordFormSection (live model)
163
+ d. subscribeSectionActivation()
164
+ subscribeFieldsSubjects() the library subscribes to each model object's
165
+ subscribeActionSubjects() events and connects its state to the form's
166
+ subscribeTableSubjects() (connectWithParentForm)
167
+ e. changeState(initialState) state machine (visibility/editability)
168
+ f. requestFormAction('GETDATA') initial data load (if loadInitialData)
169
+ g. start() app hook: callbacks are registered HERE
170
+ 4. Operation: the UI fires events → notifications on the model → callbacks
171
+ 5. Angular destroys the component → takeUntilDestroyed cleans up the subscriptions
172
+ ```
142
173
 
143
- ##### Inputs
174
+ Key points:
144
175
 
145
- This component allows to receive the following information
176
+ - **`preStart()`**: configure `name` (the form code) and route parameters.
177
+ - **`start()`**: register the callbacks (`on*`). Runs once the model is already loaded.
178
+ - **`changeState(state)`**: the **state machine** defines, for each state, which fields/actions/tables are visible and editable (`visibleStates` / `enabledStates`). Changing state re-propagates visibility and enablement to the whole view.
179
+ - **`requestFormAction(code)`**: the single point of backend communication; its response enters through `updateFormWithServerData()` and updates the existing fields/actions/tables via `updateFromServer()`.
146
180
 
147
- | Input Name | Description |
148
- | --- | ----------- |
149
- | formManager | |
150
- | icon | |
151
- | goBackAction | |
152
- | showTitle | |
153
- | headerActions | |
181
+ ---
154
182
 
155
- ##### Ouputs
183
+ ## 5. Form composition and element access
156
184
 
157
- Como salidas de este componente se genera el siguiente evento que permite determinar que desde el encabezado se solicita al formulario cerrar su operación y regresar al formulario previo.
185
+ `FormStructureAndData` (which `BasicFormComponent` extends) holds the form graph and exposes a **rich API** to access and manipulate its elements. Each element is obtained by its `code` and operated directly on the model object.
158
186
 
159
- | Input Event | Description |
160
- | --- | ----------- |
161
- | goBackEvent | |
187
+ ```typescript
188
+ // Fields → FieldDescriptor (IField)
189
+ const email = this.getField('email');
190
+ email.setValue('a@b.com');
191
+ email.required = true;
192
+ if (email.hasError()) { /* … */ }
193
+ this.getFieldValue('email'); // shortcut
194
+ this.getRequiredEmptyFields(null, 'data'); // by section
195
+
196
+ // Actions → FormAction (IAction)
197
+ const save = this.getAction('save');
198
+ this.disableAction('save');
199
+ this.getHeaderActions();
200
+
201
+ // Tables → RecordTable (ITable), with columns and table actions
202
+ const items = this.getTable('items');
203
+ items.setTableRecords(records);
204
+ items.getActions('INLINE'); // ITableAction[]
205
+ items.columns; // ITableColumn[]
206
+ const rec = this.getTableRecord('items', id);// ITableRecord
207
+
208
+ // Sections → RecordFormSection (ISection) / RecordFormSubSection (ISubSection)
209
+ this.activateSection('data');
210
+ this.getSubSection('data', 'personal');
211
+ ```
162
212
 
163
- #### SectionComponent
213
+ Element ↔ component relationship:
164
214
 
165
- ##### Inputs
215
+ | Element (model) | Contract | Base view component |
216
+ | --- | --- | --- |
217
+ | `FieldDescriptor` | `IField` | `FieldComponent` |
218
+ | `FormAction` | `IAction` | `ActionComponent` |
219
+ | `RecordTable` | `ITable` | `LibTableComponent` |
220
+ | `RecordTableColumn` / `TableAction` | `ITableColumn` / `ITableAction` | cells in `LibTableRecordFieldComponent` / `LibTableRecordActionComponent` |
221
+ | `RecordFormSection` / `RecordFormSubSection` | `ISection` / `ISubSection` | `SectionComponent` / `SubSectionComponent` |
222
+ | `FormStructureAndData` | `IForm` | `BasicFormComponent` / `FormHeaderComponent` |
166
223
 
167
- This component allows to receive the following information
224
+ Each component receives its model object via `@Input()` (`[field]`, `[action]`, `[table]`, …), registers itself as that object's *widget* and **subscribes to its changes** to reflect them; and it translates user events into notifications on that same object. In other words, **the component is a view of the model object, not its owner**.
168
225
 
169
- ######
226
+ ---
170
227
 
171
- #### SubSectionComponent
228
+ ## 6. Model objects vs. view components
172
229
 
173
- ##### Inputs
230
+ This is the most important distinction for using the library correctly:
174
231
 
175
- This component allows to receive the following information
232
+ ```
233
+ MODEL (lives for the whole form) VIEW (ephemeral, created/destroyed by Angular)
234
+ ┌───────────────────────────┐ ┌───────────────────────────┐
235
+ │ FieldDescriptor 'email' │◄── @Input ────│ FieldComponent │
236
+ │ (created in loadDefinition│ field.widget │ (created when rendered) │
237
+ │ lives until the form is │◄── subscription│ signals: value(), … │
238
+ │ closed) │ attributeChange destroyed when hidden │
239
+ └───────────────────────────┘ └───────────────────────────┘
240
+ ▲ source of truth ▲ recreated without losing data
241
+ │ getField('email') always returns the same object
242
+ ```
176
243
 
177
- | Input Name | Description |
178
- | --- | ----------- |
179
- | sectionObject | |
180
- | formManager | |
244
+ - **Model objects** (`FieldDescriptor`, `FormAction`, `RecordTable`, …) are created **once** in `loadDefinition()` and **live for as long as the form exists**. They hold the state: value, errors, visibility, selection, etc. `getField('x')` **always returns the same instance**.
245
+ - **Components** (`FieldComponent`, etc.) are **ephemeral**: Angular creates and destroys them based on what is currently shown (section change, `@if`, table paging, virtual scroll…). When destroyed and recreated, **nothing is lost**: the new component re-subscribes to the model object and recovers the current state.
181
246
 
182
- #### LibTableFilterComponent
247
+ **Practical consequences:**
183
248
 
184
- ##### Inputs
249
+ - The form's business logic operates **on the model objects** (`this.getField('x').setValue(...)`), never on the components. It works even if the component is not mounted.
250
+ - Don't keep state in the component expecting it to persist; state lives in the model.
251
+ - A model object and its component **are not the same thing**: the component is a replaceable reactive projection of the object, whereas the object is the stable, unique entity.
185
252
 
186
- This component allows to receive the following information
253
+ ---
187
254
 
188
- | Input Name | Description |
189
- | --- | ----------- |
190
- | subSection | |
191
- | showHeader | |
192
- | formManager | |
255
+ ## 7. Using the library in an Angular project
193
256
 
194
- #### LibTablePagerComponent
257
+ ### Installation
195
258
 
196
- ##### Inputs
259
+ ```bash
260
+ npm install tuain-ng-forms-lib
261
+ # or: yarn add tuain-ng-forms-lib
262
+ ```
197
263
 
198
- This component allows to receive the following information
264
+ Peer dependencies: Angular `^17` (`common`, `core`, `forms`, `router`) and `rxjs ^7.5`.
199
265
 
200
- | Input Name | Description |
201
- | --- | ----------- |
202
- | table | |
203
- | visiblePages | |
204
- | pagesGroup | |
266
+ ### a. Provide the services
205
267
 
206
- ##### Outputs
268
+ Standalone apps register them in `main.ts` (or in an `NgModule` with `providers`):
207
269
 
208
- | Output Event | Description |
209
- | --- | ----------- |
210
- | pageChanged | |
270
+ ```typescript
271
+ import { bootstrapApplication } from '@angular/platform-browser';
272
+ import { LibFormManagerService, LibFileManagementService, LibEventManagerService } from 'tuain-ng-forms-lib';
273
+ import { AppFormManager } from './services/app-form-manager.service'; // your implementation
274
+ import { AppFileManager } from './services/app-file-manager.service';
275
+
276
+ bootstrapApplication(AppComponent, {
277
+ providers: [
278
+ { provide: LibFormManagerService, useClass: AppFormManager },
279
+ { provide: LibFileManagementService, useClass: AppFileManager },
280
+ { provide: LibEventManagerService, useValue: new LibEventManagerService(['formActivity', /* … */]) },
281
+ // optional: ICON_RESOLVER, SSE_LIVE_CONNECTION_CONFIG
282
+ ],
283
+ });
284
+ ```
211
285
 
212
- #### LibTableRecordActionComponent
286
+ `AppFormManager` extends `LibFormManagerService` and implements the bridge to your backend:
213
287
 
214
- ##### Inputs
288
+ ```typescript
289
+ @Injectable()
290
+ export class AppFormManager extends LibFormManagerService {
291
+ override async getFormDefinition(formCode: string): Promise<any> { /* HTTP → JSON */ }
292
+ override async execServerAction(detail: any): Promise<any> { /* HTTP → response */ }
293
+ override goToForm(formCode: string, token: string, subject: string | null): void { /* router */ }
294
+ }
295
+ ```
215
296
 
216
- This component allows to receive the following information
297
+ ### b. Define a form
217
298
 
218
- ######
299
+ ```typescript
300
+ import { Component } from '@angular/core';
301
+ import { BasicFormComponent, LibFormManagerService, LibEventManagerService, LibFileManagementService } from 'tuain-ng-forms-lib';
302
+ import { appFormConfig } from './app-form.config'; // your IFormConfig
303
+
304
+ @Component({ standalone: true, selector: 'app-customer-form', templateUrl: './customer-form.html' })
305
+ export class CustomerFormComponent extends BasicFormComponent {
306
+ constructor(fm: LibFormManagerService, em: LibEventManagerService, fs: LibFileManagementService) {
307
+ super(fm, em, fs);
308
+ this.setConfig(appFormConfig);
309
+ }
310
+
311
+ override preStart(): void {
312
+ this.name = 'CUSTOMER'; // form code
313
+ this.formInit({ /* route params */ }); // triggers load + initialization
314
+ }
315
+
316
+ override start(): void {
317
+ // Declare HOW the form reacts:
318
+ this.onFieldValidationStart('documentId', (f) => this.validateDocument(f));
319
+ this.onActionStart('save', () => this.validateSectionConsistency('data'));
320
+ this.onActionFinish('save', () => this.goBack());
321
+ }
322
+
323
+ private validateDocument(field /* IField */): boolean {
324
+ if (field.empty) { field.setErrorMessage('Required'); return false; }
325
+ return true;
326
+ }
327
+ }
328
+ ```
219
329
 
220
- #### LibTableRecordFieldComponent
330
+ ### c. Render
221
331
 
222
- ##### Inputs
332
+ The core ships **abstract base components**: to show concrete widgets you use a Tuain UI package (e.g. `tuain-ng-forms-ant` / `tuain-ng-forms-ionic`) or your own components that **extend** `FieldComponent`, `ActionComponent`, `LibTableComponent`, etc. and supply their template. In the form template you bind each component to its model object:
223
333
 
224
- This component allows to receive the following information
334
+ ```html
335
+ <lib-form-header [form]="form" (goBackEvent)="goBack()"></lib-form-header>
225
336
 
226
- | Input Name | Description |
227
- | --- | ----------- |
228
- | fieldCode | |
229
- | fieldType | |
230
- | recordData | |
337
+ <app-field *ngFor="let f of getFields()" [field]="f"></app-field>
338
+ <app-action *ngFor="let a of getHeaderActions()" [action]="a"></app-action>
339
+ <app-table *ngFor="let t of getTables()" [table]="t"></app-table>
340
+ ```
231
341
 
232
- #### LibTableComponent
342
+ > Until the UI packages are available, the app defines its own field/action/table components by extending this library's base components and overriding `start()`/`focus()` and the template.
233
343
 
234
- ##### Inputs
344
+ ---
235
345
 
236
- This component allows to receive the following information
346
+ ## Public API
237
347
 
238
- | Input Name | Description |
239
- | --- | ----------- |
240
- | table | |
241
- | tableRecords | |
242
- | currentMode | |
243
- | waiting | |
348
+ Exported (from `tuain-ng-forms-lib`):
244
349
 
245
- ##### Outputs
246
-
247
- This component allows to generate the following events to his container
248
-
249
- | Output Event | Description |
250
- | --- | ----------- |
251
- | tableActionActivated | |
252
- | tableStartGetData | |
253
-
254
- #### BasicFormComponent
255
-
256
- ##### Methods
257
-
258
- This component is provides as the base class to define any form in the Angular application as a super-class
259
- to provide all basic form operation with a full set of methods to allow make any objects access and
260
- modifications.
261
-
262
- ##### General form operation methods
263
-
264
- This set of methods are oriented to access and modify general form attributes and configuration.
265
-
266
- | Method Name | Description |
267
- | --- | ----------- |
268
- | `supportState` | Informs if a form supports the operation on a particular state |
269
- | `supportMode`<br>*deprecated* | Informs if a form supports the operation on a particular state|
270
- | `getTitle` | Returns de form title |
271
- | `cleanData` | Cleand all fields and tables |
272
- | `displayActionServerError` | Show the error after the execution of the backend portion of an action|
273
- | `displayValidationServerError` | Show the error after the execution of the backend portion of a field validation |
274
- | `showModalDialog` | Shows a customized modal dialog|
275
- | `openUploadDialog` | Shows a standar file upload modal dialog|
276
- | `goBackForm` | Change the route of the application to go back to previous form|
277
- | `goToSubPage` | Request a new route to be displayed |
278
- | `setError` | Define the global form error|
279
- | `get formManager` | Returns the object that supports the data and structure of the form|
280
- | `resetError` | Clear the global error form object|
281
- | `getErrorType` | Returns the global form error type |
282
- | `getErrorMessage`<br>*deprecated* | Returns the global form error message |
283
- | `getErrorDetail`<br>*deprecated* | Returns the global form error detail |
284
- | `getErrorCode` | | Returns the global form error code |
285
- | `get errorMessage` | Returns the global form error message |
286
- | `get errorDetail` | Returns the global form error detail |
287
- | `getCurrentState` | Return the current state |
288
- | `getCurrentMode`<br>*deprecated* | Return the current state |
289
- | `getSubject` | Return the subject id of the form |
290
- | `getformSubject`<br>*deprecated* | Return the subject id of the form |
291
- | `errorOccured`| Return if there is an error |
292
- | `changeState` | Modify the current state |
293
-
294
- ###### Fields related methods
295
-
296
- This set of methods allow subclass to access and modify fields in the form.
297
-
298
- | Method Name | Description |
299
- | --- | ----------- |
300
- | `getFields` | Returns the form fields |
301
- | `getField` | Returns a form field object based on its name|
302
- | `enableField` | Set an status attribute of the field in order to be editable|
303
- | `disableField` | Set an status attribute of the field in order prevent edition |
304
- | `getFieldValue` | Returns the value of a field |
305
- | `getFieldOptions` | Returns an array with all posible values of the field with a description text|
306
- | `setFieldValue` | Change the current value of a field |
307
- | `setFieldErrorMessage` | Defines an error message for a field |
308
- | `setFieldOptions` | Define the posible values of the field with an array of values and description text |
309
- | `setFieldRequired` | Change an status attribute of the field to determine if it is required |
310
- | `applyProcessToFieldSet` | Execute a process on all the fields specified in an array, section or sub-section. If the fields are not specified, the execition will be over the whole set of fields in the form `(processFunc, fieldArray?, sectionCode?, subSectionCode?)`|
311
- | `cleanFields` | Clean all the fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
312
- | `getRequiredFields` | Obtain all the required fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
313
- | `getRequiredEmptyFields` | Obtain all the required and empty fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
314
- | `getChangedFields` | Obtain all the fields that changed since the last backend refresh over a field set specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
315
- | `getFieldsWithValidationIssues` | Obtain all the fields that has validation errors over a field set specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
316
- | `tagFieldsWithError` | Set an error mesagge for all the fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(errorMessage, fieldArray?, sectionCode?, subSectionCode?)`|
317
- | `cleanErrorFields` | Clean the error on all the fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
318
- | `showLabelFields` | Show the label on all the fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
319
- | `hideLabelFields` | Hide the label on all the fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
320
- | `enableFields` | Enable for edition all the fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
321
- | `disableFields` | Disable for edition all the fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
322
- | `showFields` | Show all the fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
323
- | `hideFields` | Hide all the fields specified in an array, section or sub-section using their default value. If the fields are not specified, the execition will be over the whole set of fields in the form `(fieldArray?, sectionCode?, subSectionCode?)`|
324
- | `showFieldInfo` | Show help information related with a field |
325
- | `addFieldInputValidation` | `(fields, callbackMethod)`|
326
- | `addFieldValidationStart` | Defines a callback function to be triggered when a field change its content in order to be validated. The returned value of this callback defines if the process must continue in the backend|
327
- | `addFieldValidationFinish` | Defines a callback function to be triggered when the field validation process returns from the backend portion execution in order to be completed |
328
- | `startFieldInputValidation` | Defines a callback function to be triggered when a field receive any input and is change is not complete, so the user typing can be verified and validated. This process do not have any backend process by default
329
- | `startFieldValidation` | Start the field validation process|
330
- | `startServerFieldValidation` | Trigger the execution of a field validation, starting on the backend portion without the first callbacks execution|
331
-
332
- ###### Actions related methods
333
-
334
- This set of methods allow subclass to access and modify actions in the form.
335
-
336
- | Method Name | Description |
337
- | --- | ----------- |
338
- | `getHeaderActions` | Returns the form actions defined to be placed on the form header|
339
- | `getAction` | Returns a form action object based on its name|
340
- | `showAction` | Change the visibility of an action to be displayed based on its name|
341
- | `hideAction` | Change the visibility of an action to be hidden based on its name|
342
- | `showActions` | Change the visibility of an action set to be displayed based on an array of names|
343
- | `hideActions` | Change the visibility of an action set to be hidden based on an array of names|
344
- | `enableAction` | Modify the status of an action to be available for execution|
345
- | `disableAction` | Modify the status of an action to prevent execution|
346
- | `enableActions` | Modify the status of an actionset to be available for execution based on an array of names|
347
- | `disableActions` | Modify the status of an action to prevent execution based on an array of names|
348
- | `addActionMethodStart` | Defines a callback function to be triggered when an action is requested. The returned value of this callback defines if the process must continue in the backend|
349
- | `addActionMethodFinish` | Defines a callback function to be triggered when an action returns from the backend portion execution in order to be completed |
350
- | `startAction` | Start the execution of an action, starting with the initial callbacks, continuing in the backend if former callbacks were ok and execuing the after backend callbacks|
351
- | `startServerAction` | Trigger the execution of an action, starting on the backend portion without the first callbacks execution|
352
-
353
- ###### Tables related methods
354
-
355
- This set of methods allow subclass to access and modify tables in the form.
356
-
357
- | Method Name | Description |
358
- | --- | ----------- |
359
- | `getTables` | Returns all form tables |
360
- | `getTable` | Returns a form table object based on its name |
361
- | `showTable` | Change the visibility of a table to be displayed based on its name |
362
- | `hideTable` | Change the visibility of a table to be hidden based on its name|
363
- | `showTables` | Change the visibility of a table set to be displayed based on an array of names|
364
- | `hideTables` | Change the visibility of a table set to be hidden based on an array of names|
365
- | `cleanTable` | Delete the content of a table |
366
- | `getTableRecord` | Returns an `array` with all records of a table|
367
- | `displayTableServerError` | Shows an error message with the result of a table action on the backend|
368
- | `addTableActionStart` | Defines a callback function to be triggered when an action of the table is requested. The returned value of this callback defines if the process must continue in the backend|
369
- | `addTableActionFinish` | Defines a callback function to be triggered when an action of the table returns from the backend portion execution in order to be completed |
370
- | `addTableGetDataStart` | Defines a callback function to be triggered when the table need to refresh or update its data as a consequence of pagination or any refresh request|
371
- | `addTableGetDataFinish` | Defines a callback function to be triggered when the table data refresh or update is executed on the backend|
372
- | `startTableAction` | Start the execution of a table action, starting with the callback actions, continue in the backend if former callbacks were ok and execute the after backend callbacks|
373
- | `startTableServerAction` | Trigger the execution of a table action, starting on the backend portion without the first callbacks execution|
374
- | `startTableGetData` | Start the execution of a table get data action, starting with the callback actions, continue in the backend if former callbacks were ok and execute the after backend callbacks|
375
- | `startTableServerGetData` | Trigger the execution of a table get data action, starting on the backend portion without the first callbacks execution|
376
-
377
- ###### Sections related methods
378
-
379
- This set of methods allow subclass to access and modify fields in the form.
380
-
381
- | Method Name | Description |
382
- | --- | ----------- |
383
- | `getSections` | Returns all form sections |
384
- | `getSection` | Returns the section object based on its name |
385
- | `activateSection` | Set a section as the active one based on its name |
386
- | `activeSection` | Returns the name of the active section |
387
- | `getSubSection` | Returns the sub-ection object based on the section name and subsection name |
388
- | `getSectionsTitles` | Returns an array with all section titles |
389
- | `showSection` | Change the visibility of a section to be displayed based on its name |
390
- | `hideSection` | Change the visibility of a section to be hidden based on its name |
391
- | `showSections` | Change the visibility of a section set to be displayed based on an array of names|
392
- | `hideSections` | Change the visibility of a section set to be hidden based on an array of names|
393
- | `showSubSection` | Change the visibility of a sub-section to be displayed based on the section name and subsection name|
394
- | `hideSubSection` | Change the visibility of a sub-section to be hidden based on the section name and subsection name|
395
- | `addSectionActivation` | Defines a callback function to be triggered when any of the sections with name in the input array of section names is activated|
396
- | `addSectionInactivation` | Defines a callback function to be triggered when any of the sections with name in the input array of section names is inactivated|
397
- | `checkSectionRequiredFields` | Return a list of a section based on its name, with the required fields that are empty |
398
- | `validateSectionConsistency` | Verify that all required fields have value and don't have any validation errors |
399
-
400
- ###### Utilities and complex methods
401
-
402
- This set of methods interact with multiple element types to provide tools to simplify complex
403
- but common operations in the forms.
404
-
405
- | Method Name | Description |
406
- | --- | ----------- |
407
- | `copyTableRecordToFields` | Copy all columns in a table record to a set of fields using a mapping objec to relate column names with field names. If the mapping object is not present, look for fields with same names|
408
- | `defineEditionTable` | Configure an object to copy fields, enable edition, hide fields and actions to operate table and fields for records edition|
350
+ - **Model:** `FormStructureAndData`, `FieldDescriptor`, `FormAction`, `RecordTable`, `RecordTableColumn`, `TableAction`, `TableRecordData`, `RecordFormSection`, `RecordFormSubSection`, and the bases `FormPiece`/`FormPiecePropagate`/`FormElement`.
351
+ - **Contracts:** `IForm`, `IField`, `IAction`, `ITable`, `ITableColumn`, `ITableAction`, `ITableRecord`, `ISection`, `ISubSection`, `IFormPiece`/`IFormElement`, `IFormConfig` and the definition/event types.
352
+ - **Base components (standalone):** `BasicFormComponent`, `FieldComponent`, `ActionComponent`, `LibTableComponent`, `LibTableRecordFieldComponent`, `LibTableRecordActionComponent`, `SectionComponent`, `SubSectionComponent`, `FormHeaderComponent`, `FormErrorComponent`, `ElementComponent`, `PieceComponent`.
353
+ - **Services and tokens:** `LibFormManagerService`, `LibEventManagerService`, `LibFileManagementService`, `BaseIconResolverService` + `ICON_RESOLVER`, `SseLiveConnectionService` + `SSE_LIVE_CONNECTION_CONFIG`.
409
354
 
410
355
  ## License
411
356