@praxisui/dynamic-fields 9.0.0-rc.3 → 9.0.0-rc.4
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/ai/component-registry.json +2 -2
- package/docs/dynamic-fields-field-selection-guide.md +2 -0
- package/fesm2022/praxisui-dynamic-fields.mjs +24 -3
- package/package.json +3 -3
- package/src/lib/components/material-async-select/pdx-material-async-select.json-api.md +2 -0
- package/types/praxisui-dynamic-fields.d.ts +2 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
|
-
"generatedAt": "2026-07-
|
|
3
|
+
"generatedAt": "2026-07-26T03:19:30.955Z",
|
|
4
4
|
"packageName": "@praxisui/dynamic-fields",
|
|
5
|
-
"packageVersion": "9.0.0-rc.
|
|
5
|
+
"packageVersion": "9.0.0-rc.4",
|
|
6
6
|
"sourceRegistry": "praxis-component-registry-ingestion",
|
|
7
7
|
"sourceRegistryVersion": "1.0.0",
|
|
8
8
|
"componentCount": 76,
|
|
@@ -149,6 +149,8 @@ Checklist minimo para promocao:
|
|
|
149
149
|
- o recurso oferece busca paginada e reidratacao por ids (`filter` e `byIds`) para valores salvos;
|
|
150
150
|
- `selectionPolicy` documenta status, elegibilidade e preservacao de valor historico quando aplicavel;
|
|
151
151
|
- dependencias entre entidades usam `dependsOn` e `dependencyFilterMap`, sem inferencia por nome de campo no Angular;
|
|
152
|
+
- ao mudar uma dependencia canonica, o runtime limpa por padrao a selecao dependente, emite a alteracao para continuar a cascata e preserva apenas o valor hidratado na montagem inicial;
|
|
153
|
+
- use `selectionPolicy.allowRetainInvalidExistingValue=true` somente quando o dominio permitir manter explicitamente uma selecao historica fora do novo conjunto de opcoes;
|
|
152
154
|
- surfaces de detalhe sao publicadas pelo recurso quando `navigateToDetail` estiver habilitado;
|
|
153
155
|
- existe demo jogavel cobrindo campo de formulario e, quando o uso for filtro, `inlineEntityLookup`;
|
|
154
156
|
- existe teste focal ou e2e cobrindo busca, selecao, reidratacao e estado bloqueado/historico;
|
|
@@ -4340,15 +4340,21 @@ class SimpleBaseSelectComponent extends SimpleBaseInputComponent {
|
|
|
4340
4340
|
const debounceMs = Number(meta.dependencyDebounceMs ?? this.global.getDynamicFields()?.cascade?.debounceMs ?? 150);
|
|
4341
4341
|
const mergeStrategy = meta.dependencyMergeStrategy ?? 'merge';
|
|
4342
4342
|
const loadOnChange = meta.dependencyLoadOnChange ?? this.global.getDynamicFields()?.cascade?.loadOnChange ?? 'respectLoadOn';
|
|
4343
|
+
let dependencySnapshotInitialized = false;
|
|
4343
4344
|
// Subscribe to combined changes
|
|
4344
4345
|
this.dependencySub = combineLatest(streams)
|
|
4345
4346
|
.pipe(debounceTime(debounceMs))
|
|
4346
4347
|
.subscribe((values) => {
|
|
4347
4348
|
const availableControls = controls.filter((entry) => !!entry.control);
|
|
4348
4349
|
const fragment = this.applyDependencyValues(meta, availableControls, values);
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4350
|
+
const isInitialDependencySnapshot = !dependencySnapshotInitialized;
|
|
4351
|
+
dependencySnapshotInitialized = true;
|
|
4352
|
+
if (!isInitialDependencySnapshot &&
|
|
4353
|
+
this.shouldResetOnDependencyChange(meta) &&
|
|
4354
|
+
this.hasMeaningfulSelectValue(this.control().value)) {
|
|
4355
|
+
const emptyValue = this.multiple() ? [] : null;
|
|
4356
|
+
this.setValue(emptyValue, { emitEvent: true });
|
|
4357
|
+
this.control().markAsDirty();
|
|
4352
4358
|
}
|
|
4353
4359
|
// Trigger reload according to strategy
|
|
4354
4360
|
if (!this.resourcePath())
|
|
@@ -4375,6 +4381,21 @@ class SimpleBaseSelectComponent extends SimpleBaseInputComponent {
|
|
|
4375
4381
|
});
|
|
4376
4382
|
});
|
|
4377
4383
|
}
|
|
4384
|
+
shouldResetOnDependencyChange(meta) {
|
|
4385
|
+
if (meta.resetOnDependentChange !== undefined) {
|
|
4386
|
+
return meta.resetOnDependentChange === true;
|
|
4387
|
+
}
|
|
4388
|
+
const hasCanonicalDependencies = Array.isArray(meta.optionSource?.dependsOn) &&
|
|
4389
|
+
meta.optionSource.dependsOn.length > 0;
|
|
4390
|
+
const retainsInvalidExistingValue = meta.optionSource?.selectionPolicy?.allowRetainInvalidExistingValue === true;
|
|
4391
|
+
return hasCanonicalDependencies && !retainsInvalidExistingValue;
|
|
4392
|
+
}
|
|
4393
|
+
hasMeaningfulSelectValue(value) {
|
|
4394
|
+
if (Array.isArray(value)) {
|
|
4395
|
+
return value.length > 0;
|
|
4396
|
+
}
|
|
4397
|
+
return value !== null && value !== undefined && value !== '';
|
|
4398
|
+
}
|
|
4378
4399
|
extractDependencyValue(raw, path) {
|
|
4379
4400
|
if (raw == null)
|
|
4380
4401
|
return raw;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisui/dynamic-fields",
|
|
3
|
-
"version": "9.0.0-rc.
|
|
3
|
+
"version": "9.0.0-rc.4",
|
|
4
4
|
"description": "Angular Material-based dynamic form fields for Praxis UI with lazy loading and metadata-driven rendering.",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/common": "^21.0.0",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"@angular/platform-browser": "^21.0.0",
|
|
12
12
|
"@angular/router": "^21.0.0",
|
|
13
13
|
"rxjs": "^7.8.0",
|
|
14
|
-
"@praxisui/core": "^9.0.0-rc.
|
|
15
|
-
"@praxisui/cron-builder": "^9.0.0-rc.
|
|
14
|
+
"@praxisui/core": "^9.0.0-rc.4",
|
|
15
|
+
"@praxisui/cron-builder": "^9.0.0-rc.4"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"libphonenumber-js": "^1.12.41",
|
|
@@ -416,6 +416,8 @@ Notas de runtime:
|
|
|
416
416
|
- em `optionSource`, o filtro envia `includeIds` somente quando `optionSource.includeIds=true` e nao ha termo de busca ativo; quando ausente, `false` ou durante busca digitada, valores selecionados sao reidratados por `/option-sources/{sourceKey}/options/by-ids`.
|
|
417
417
|
- durante busca digitada, a lista visivel usa apenas os itens da pagina remota filtrada. Opcoes reidratadas por ID preservam o display fechado, mas nao podem substituir ou inflar o resultado da busca.
|
|
418
418
|
- em `optionSource`, dependencias declaradas por `dependsOn` e `dependencyFilterMap` sao materializadas como filtros estruturados `equals` no envelope canonico de opcoes.
|
|
419
|
+
- depois da montagem inicial, a mudanca de qualquer dependencia canonica limpa o valor selecionado e o texto exibido antes de recarregar as opcoes. A limpeza emite `valueChanges` para invalidar dependentes posteriores na mesma cadeia.
|
|
420
|
+
- `optionSource.selectionPolicy.allowRetainInvalidExistingValue=true` permite reter explicitamente um valor historico; `resetOnDependentChange=false` permanece como opt-out de compatibilidade para metadata legado.
|
|
419
421
|
- `onSearch` limpa estado local e reinicia pagina para novo termo.
|
|
420
422
|
- `loadMore` nao inicia a primeira carga remota; a primeira pagina respeita `loadOn`, abertura do painel, reload explicito ou mudanca de dependencia.
|
|
421
423
|
- `loadMore` incrementa pagina somente quando ja existe pagina remota carregada e `endReached=false`.
|
|
@@ -1283,6 +1283,8 @@ declare abstract class SimpleBaseSelectComponent<T = any> extends SimpleBaseInpu
|
|
|
1283
1283
|
private ensureCurrentValueLoaded;
|
|
1284
1284
|
/** (Re)configure dependency observers based on metadata and current FormGroup */
|
|
1285
1285
|
protected setupDependencies(): void;
|
|
1286
|
+
private shouldResetOnDependencyChange;
|
|
1287
|
+
private hasMeaningfulSelectValue;
|
|
1286
1288
|
protected extractDependencyValue(raw: any, path?: string): any;
|
|
1287
1289
|
protected applyDependencyCriteria(fragment: Record<string, any>, strategy?: 'merge' | 'replace'): void;
|
|
1288
1290
|
protected onDependenciesChanged(): void;
|