ngx-dynamic-entity 1.8.1 → 1.9.1

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.
package/README.md CHANGED
@@ -25,7 +25,9 @@ No Angular Material required. This package has no dependency on Material or the
25
25
  - **`DynamicRecordFormComponent`** — record editor with summary drawer (`showOnMinimize`), profile header, and per-section saving.
26
26
  - **Reactive rules** — real-time condition evaluation driving field/tab visibility, validation errors and warnings, and info banners.
27
27
  - **Entity references & cascades** — consumer-registered loaders, parent→child dropdown filtering, and `autoPatch` record copying.
28
- - **20 field types** — each a standalone component, registered explicitly so unused types are never bundled.
28
+ - **21 field types** — each a standalone component, registered explicitly so unused types are never bundled.
29
+ - **Fully translatable** — config text is `LocalizedText`; the library's own buttons and empty states resolve through `uiText`.
30
+ - **Configurable masking and dates** — `MASKED_PLACEHOLDER` replaces the `XXXXXXXXX` literal; `setDateFormatters` in `@dynamic-entity/core` replaces the browser-locale date punctuation.
29
31
 
30
32
  ---
31
33
 
@@ -61,6 +63,68 @@ provideFieldTypes({ text: TextFieldComponent, dropdown: DropdownFieldComponent }
61
63
 
62
64
  Multiple `provideFieldTypes` calls merge; on a key collision the later registration wins. Pass your own component for a key to override a built-in, or add a key of your own for a custom type.
63
65
 
66
+ Some field types take an optional collaborator. A `markdown` field renders its source as
67
+ text until you register a renderer — see
68
+ [Markdown](../../EXTENDING.md#markdown) for `MARKDOWN_RENDERER`, which is any function from
69
+ source to HTML.
70
+
71
+ ---
72
+
73
+ ## 🌍 Translating the library's own text
74
+
75
+ Labels, placeholders and options come from your config as `LocalizedText` and already follow
76
+ the `language` input. The chrome around them — Save, Reset, "No rows yet." — is the
77
+ library's, and resolves through `uiText`:
78
+
79
+ ```typescript
80
+ import { provideNgxDynamicEntity } from 'ngx-dynamic-entity';
81
+
82
+ export const providers = provideNgxDynamicEntity({
83
+ uiText: {
84
+ save: { en: 'Save', de: 'Speichern' },
85
+ reset: { en: 'Reset', de: 'Zurücksetzen' },
86
+ },
87
+ });
88
+ ```
89
+
90
+ Values may be `LocalizedText`, a flat string, or — for an app that already has ngx-translate,
91
+ Transloco or `$localize` — a resolver `(key, defaultText, language) => string` provided
92
+ through `UI_TEXT`. Resolution is per key: anything you leave out keeps its English default.
93
+ `DEFAULT_UI_TEXT` exports every key with its English source string, so a translation file can
94
+ be generated from it. See [i18n](../../EXTENDING.md#validation-messages-and-i18n).
95
+
96
+ ---
97
+
98
+ ## 🎭 Masked placeholder and dates
99
+
100
+ A masked field shows `XXXXXXXXX` unless you replace it. The real value stays in the control
101
+ either way — see [Security](#-security).
102
+
103
+ ```typescript
104
+ import { ApplicationConfig } from '@angular/core';
105
+ import { MASKED_PLACEHOLDER, provideNgxDynamicEntity } from 'ngx-dynamic-entity';
106
+
107
+ export const maskedPlaceholderConfig: ApplicationConfig = {
108
+ providers: [
109
+ provideNgxDynamicEntity({}),
110
+ { provide: MASKED_PLACEHOLDER, useValue: '••••••••' },
111
+ ],
112
+ };
113
+ ```
114
+
115
+ `date` / `datetime` / `time` still format in the browser's locale. To use the form's
116
+ `language`, or a fixed format, call `setDateFormatters` from `@dynamic-entity/core`:
117
+
118
+ ```typescript
119
+ import { setDateFormatters } from '@dynamic-entity/core';
120
+
121
+ setDateFormatters({
122
+ date: (value, lang) => value.toLocaleDateString(lang ?? []),
123
+ });
124
+ ```
125
+
126
+ A partial object overrides one kind; `setDateFormatters()` restores the defaults.
127
+
64
128
  ---
65
129
 
66
130
  ## 💡 Usage
@@ -100,6 +164,51 @@ Multiple `provideFieldTypes` calls merge; on a key collision the later registrat
100
164
 
101
165
  ---
102
166
 
167
+ ## 📄 Three ways to present a record
168
+
169
+ `DynamicFormComponent` is the editable form. `DynamicRecordFormComponent` renders the same
170
+ config as a record, and two of its inputs decide how much a reader may do:
171
+
172
+ | Presentation | Component | Inputs |
173
+ |---|---|---|
174
+ | **Form** | `ngx-dynamic-form` | editable controls plus the actions block |
175
+ | **Record view** | `ngx-dynamic-record-form` | `viewMode` (default `true`) — values, with a per-tab "Edit section" flow |
176
+ | **Data only** | `ngx-dynamic-record-form` | `isReadOnly="true"` — values, and no way to edit them |
177
+
178
+ ```html
179
+ <!-- Read-only for everyone, whatever their roles allow. -->
180
+ <ngx-dynamic-record-form
181
+ [config]="config"
182
+ [initialData]="record"
183
+ [userRoles]="roles"
184
+ [isReadOnly]="true"
185
+ ></ngx-dynamic-record-form>
186
+ ```
187
+
188
+ `viewMode="false"` gives a directly editable record with no view/edit distinction, for hosts
189
+ that do not want the section flow.
190
+
191
+ ### Record-form inputs
192
+
193
+ | Input | Type | Notes |
194
+ |---|---|---|
195
+ | `config` / `initialData` / `userRoles` / `language` | — | As the form component. |
196
+ | `viewMode` | `boolean` | Default `true`. Read-only with a per-tab edit flow. |
197
+ | `isReadOnly` | `boolean` | Whole record read-only, with no edit affordance at all. |
198
+ | `readOnlyFields` | `string[]` | Specific ids read-only while the rest stays editable. |
199
+ | `rules` | `FormRule[]` | Optional reactive rules. |
200
+
201
+ | Output | Payload |
202
+ |---|---|
203
+ | `formSubmit` / `formChange` / `formReset` | As the form component. |
204
+ | `sectionSave` | `{ tabId, record }` — one tab was saved. |
205
+
206
+ **RBAC applies on top of all three.** Roles outside `permissions.edit` get a read-only
207
+ record whichever presentation you choose — see [Security](#-security), because that is a
208
+ rendering decision, not an access-control boundary.
209
+
210
+ ---
211
+
103
212
  ## 🗂 Record shape
104
213
 
105
214
  A record is **nested by tab id** by default:
@@ -120,7 +229,7 @@ This applies in both directions — `initialData` is read with it and `formSubmi
120
229
 
121
230
  ## 🔐 Security
122
231
 
123
- `userRoles`, `EntityPermissions`, and `maskData` affect **rendering only**. A masked field displays `XXXXXXXXX` while the real value stays in the form control and is included in the `formSubmit` payload. Enforce authorization on the server and never send a user data they may not see.
232
+ `userRoles`, `EntityPermissions`, and `maskData` affect **rendering only**. A masked field displays `XXXXXXXXX` by default (`MASKED_PLACEHOLDER` overrides the text) while the real value stays in the form control and is included in the `formSubmit` payload. Enforce authorization on the server and never send a user data they may not see.
124
233
 
125
234
  ---
126
235