@praxisui/dynamic-fields 9.0.0-beta.81 → 9.0.0-beta.83

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-07-19T23:44:00.907Z",
3
+ "generatedAt": "2026-07-20T14:11:58.169Z",
4
4
  "packageName": "@praxisui/dynamic-fields",
5
- "packageVersion": "9.0.0-beta.81",
5
+ "packageVersion": "9.0.0-beta.83",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 76,
@@ -4170,6 +4170,8 @@ class SimpleBaseSelectComponent extends SimpleBaseInputComponent {
4170
4170
  if (!this.crudService || !this.resourcePath()) {
4171
4171
  return;
4172
4172
  }
4173
+ this.synchronizeDependencyCriteriaFromControls();
4174
+ criteria = this.filterCriteria();
4173
4175
  const filter = { ...criteria };
4174
4176
  if (searchTerm && !this.optionSource()) {
4175
4177
  filter[this.optionLabelKey()] = searchTerm;
@@ -4367,53 +4369,14 @@ class SimpleBaseSelectComponent extends SimpleBaseInputComponent {
4367
4369
  if (!streams.length)
4368
4370
  return;
4369
4371
  const debounceMs = Number(meta.dependencyDebounceMs ?? this.global.getDynamicFields()?.cascade?.debounceMs ?? 150);
4370
- const valuePathCfg = this.resolveDependencyValuePathConfig(meta);
4371
- const mapCfg = this.resolveDependencyFilterMap(meta);
4372
4372
  const mergeStrategy = meta.dependencyMergeStrategy ?? 'merge';
4373
4373
  const loadOnChange = meta.dependencyLoadOnChange ?? this.global.getDynamicFields()?.cascade?.loadOnChange ?? 'respectLoadOn';
4374
4374
  // Subscribe to combined changes
4375
4375
  this.dependencySub = combineLatest(streams)
4376
4376
  .pipe(debounceTime(debounceMs))
4377
4377
  .subscribe((values) => {
4378
- // Build fragment from all deps
4379
- const fragment = {};
4380
- controls
4381
- .filter((c) => !!c.control)
4382
- .forEach((c, idx) => {
4383
- const raw = values[idx];
4384
- // Determine valuePath for this dep
4385
- let valuePath;
4386
- if (valuePathCfg && typeof valuePathCfg === 'object') {
4387
- valuePath = valuePathCfg[c.name];
4388
- }
4389
- else if (typeof valuePathCfg === 'string') {
4390
- valuePath = valuePathCfg;
4391
- }
4392
- else {
4393
- // default: use this component's optionValueKey or 'id'
4394
- valuePath = this.optionValueKey?.() || 'id';
4395
- }
4396
- const extracted = this.extractDependencyValue(raw, valuePath);
4397
- // Determine key mapping
4398
- const mapEntry = mapCfg?.[c.name] ?? c.name;
4399
- const targetKey = typeof mapEntry === 'string' ? mapEntry : mapEntry?.key ?? c.name;
4400
- if (extracted == null || (Array.isArray(extracted) && extracted.length === 0)) {
4401
- // remove mapped key when null/empty
4402
- this.applyDependencyCriteria({ __remove__: targetKey }, mergeStrategy);
4403
- return;
4404
- }
4405
- // Support dot-path keys (e.g., 'rota.id')
4406
- const fragRoot = {};
4407
- this.setByPath(fragRoot, targetKey, extracted);
4408
- // Shallow merge fragment root-level keys
4409
- Object.keys(fragRoot).forEach((k) => {
4410
- fragment[k] = this.mergeObjectsDeep(fragment[k], fragRoot[k]);
4411
- });
4412
- });
4413
- // Apply built fragment
4414
- if (Object.keys(fragment).length > 0) {
4415
- this.applyDependencyCriteria(fragment, mergeStrategy);
4416
- }
4378
+ const availableControls = controls.filter((entry) => !!entry.control);
4379
+ const fragment = this.applyDependencyValues(meta, availableControls, values);
4417
4380
  // Reset value when configured
4418
4381
  if (meta.resetOnDependentChange) {
4419
4382
  this.setValue(null, { emitEvent: false });
@@ -4501,9 +4464,62 @@ class SimpleBaseSelectComponent extends SimpleBaseInputComponent {
4501
4464
  return meta.optionSource?.valuePropertyPath;
4502
4465
  }
4503
4466
  optionSourceByIdsOptions() {
4467
+ this.synchronizeDependencyCriteriaFromControls();
4504
4468
  const filter = this.filterCriteria();
4505
4469
  return filter && Object.keys(filter).length ? { filter } : undefined;
4506
4470
  }
4471
+ /** Keeps every request aligned with the dependency values currently bound to the form. */
4472
+ synchronizeDependencyCriteriaFromControls() {
4473
+ const meta = this.metadata();
4474
+ if (!meta || !this.resourcePath())
4475
+ return;
4476
+ const enabled = meta.enableDependencyCascade ??
4477
+ (this.global.getDynamicFields()?.cascade?.enable ?? true);
4478
+ const dependencies = this.resolveDependencyFields(meta);
4479
+ if (!dependencies?.length || enabled === false)
4480
+ return;
4481
+ const form = this.control()?.parent ?? null;
4482
+ if (!form)
4483
+ return;
4484
+ const controls = dependencies
4485
+ .map((name) => ({ name, control: form.get(name) ?? null }))
4486
+ .filter((entry) => !!entry.control);
4487
+ if (!controls.length)
4488
+ return;
4489
+ this.applyDependencyValues(meta, controls, controls.map((entry) => entry.control.value));
4490
+ }
4491
+ applyDependencyValues(meta, controls, values) {
4492
+ const fragment = {};
4493
+ const valuePathConfig = this.resolveDependencyValuePathConfig(meta);
4494
+ const filterMap = this.resolveDependencyFilterMap(meta);
4495
+ const mergeStrategy = meta.dependencyMergeStrategy ?? 'merge';
4496
+ controls.forEach((entry, index) => {
4497
+ const raw = values[index];
4498
+ const valuePath = valuePathConfig && typeof valuePathConfig === 'object'
4499
+ ? valuePathConfig[entry.name]
4500
+ : typeof valuePathConfig === 'string'
4501
+ ? valuePathConfig
4502
+ : this.optionValueKey?.() || 'id';
4503
+ const extracted = this.extractDependencyValue(raw, valuePath);
4504
+ const mapEntry = filterMap?.[entry.name] ?? entry.name;
4505
+ const targetKey = typeof mapEntry === 'string'
4506
+ ? mapEntry
4507
+ : mapEntry?.key ?? entry.name;
4508
+ if (extracted == null || (Array.isArray(extracted) && extracted.length === 0)) {
4509
+ this.applyDependencyCriteria({ __remove__: targetKey }, mergeStrategy);
4510
+ return;
4511
+ }
4512
+ const mapped = {};
4513
+ this.setByPath(mapped, targetKey, extracted);
4514
+ Object.keys(mapped).forEach((key) => {
4515
+ fragment[key] = this.mergeObjectsDeep(fragment[key], mapped[key]);
4516
+ });
4517
+ });
4518
+ if (Object.keys(fragment).length) {
4519
+ this.applyDependencyCriteria(fragment, mergeStrategy);
4520
+ }
4521
+ return fragment;
4522
+ }
4507
4523
  // Helpers: object path ops and merges
4508
4524
  getByPath(obj, dotPath) {
4509
4525
  if (!obj || !dotPath)
@@ -13097,6 +13113,7 @@ class MaterialAsyncSelectComponent extends SimpleBaseSelectComponent {
13097
13113
  if (!this.crudService || !this.hasRemoteOptionsContract()) {
13098
13114
  return of(void 0);
13099
13115
  }
13116
+ this.synchronizeDependencyCriteriaFromControls();
13100
13117
  const term = this.termControl.value || '';
13101
13118
  const hasSearchTerm = !!term.trim();
13102
13119
  const optionSource = this.optionSource();
@@ -26985,6 +27002,8 @@ class MaterialSearchableSelectComponent extends SimpleBaseSelectComponent {
26985
27002
  if (!this.crudService || !this.resourcePath()) {
26986
27003
  return;
26987
27004
  }
27005
+ this.synchronizeDependencyCriteriaFromControls();
27006
+ criteria = this.filterCriteria();
26988
27007
  const optionSource = this.optionSource();
26989
27008
  const filter = { ...criteria };
26990
27009
  if (searchTerm && !optionSource) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxisui/dynamic-fields",
3
- "version": "9.0.0-beta.81",
3
+ "version": "9.0.0-beta.83",
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-beta.81",
15
- "@praxisui/cron-builder": "^9.0.0-beta.81"
14
+ "@praxisui/core": "^9.0.0-beta.83",
15
+ "@praxisui/cron-builder": "^9.0.0-beta.83"
16
16
  },
17
17
  "dependencies": {
18
18
  "libphonenumber-js": "^1.12.41",
@@ -1296,6 +1296,9 @@ declare abstract class SimpleBaseSelectComponent<T = any> extends SimpleBaseInpu
1296
1296
  protected optionSourceByIdsOptions(): {
1297
1297
  filter?: Record<string, unknown>;
1298
1298
  } | undefined;
1299
+ /** Keeps every request aligned with the dependency values currently bound to the form. */
1300
+ protected synchronizeDependencyCriteriaFromControls(): void;
1301
+ private applyDependencyValues;
1299
1302
  private getByPath;
1300
1303
  private setByPath;
1301
1304
  private unsetByPath;