@gravitee/ui-particles-angular 17.7.1-fix-apim-12804-endpoint-group-headers-sync-e307a3e → 17.7.1-improve-displayif-disabledif-84d4eec

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.
@@ -3000,15 +3000,8 @@ class GioFormlyJsonSchemaService {
3000
3000
  mappedField.expressions = {
3001
3001
  ...mappedField.expressions,
3002
3002
  hide: field => {
3003
- let parentField = field;
3004
- while (parentField.parent) {
3005
- parentField = parentField.parent;
3006
- }
3007
3003
  try {
3008
- return !displayIf({
3009
- value: parentField.model,
3010
- context,
3011
- });
3004
+ return !displayIf({ field, context });
3012
3005
  }
3013
3006
  catch (e) {
3014
3007
  // Ignore the error and display the field
@@ -3108,15 +3101,8 @@ class GioFormlyJsonSchemaService {
3108
3101
  // if the parent is already disabled there is no need to change anything at the child level
3109
3102
  return false;
3110
3103
  }
3111
- let parentField = field;
3112
- while (parentField.parent) {
3113
- parentField = parentField.parent;
3114
- }
3115
3104
  try {
3116
- const isDisabled = disableIf({
3117
- value: parentField.model,
3118
- context,
3119
- });
3105
+ const isDisabled = disableIf({ field, context });
3120
3106
  // Useful when full form is re-enabled to sync the fromControl enable/disable state
3121
3107
  isDisabled ? field.formControl?.disable({ emitEvent: false }) : field.formControl?.enable({ emitEvent: false });
3122
3108
  return isDisabled;
@@ -3276,18 +3262,90 @@ const getGioIf = (gioIf) => {
3276
3262
  if (isNil($eq) || !isObject($eq)) {
3277
3263
  return undefined;
3278
3264
  }
3279
- return objectToCheck => {
3280
- if (isEmpty(objectToCheck)) {
3265
+ return ({ field, context }) => {
3266
+ if (!field) {
3281
3267
  return false;
3282
3268
  }
3283
3269
  return Object.entries($eq)
3284
3270
  .map(([k, v]) => ({ path: k, eqValue: castArray(v) }))
3285
3271
  .every(({ path, eqValue }) => {
3286
- const value = get(objectToCheck, path);
3272
+ const value = resolveGioIfPath(path, field, context);
3287
3273
  return eqValue.includes(value);
3288
3274
  });
3289
3275
  };
3290
3276
  };
3277
+ /**
3278
+ * Resolves a `displayIf` / `disableIf` path against the form state.
3279
+ *
3280
+ * Path syntax (backward compatible):
3281
+ * - `value.<dotPath>` / `context.<dotPath>` → root model / external context (legacy)
3282
+ * - `./<dotPath>` → current scope (`field.model`)
3283
+ * - `../<dotPath>` (any depth) → walks up the ancestor chain by one
3284
+ * scope per `..`, where a "scope" is an
3285
+ * ancestor whose `model` differs from
3286
+ * the previous one (Formly wrappers that
3287
+ * share the same model are skipped).
3288
+ *
3289
+ * Relative paths let conditions inside an array item (or a sub-object of an item)
3290
+ * reference siblings or item-level fields, which is impossible with `value.` since
3291
+ * the array index of the current row is unknown.
3292
+ */
3293
+ const resolveGioIfPath = (path, field, context) => {
3294
+ if (path === 'value' || path.startsWith('value.')) {
3295
+ const root = getRootModel(field);
3296
+ return path === 'value' ? root : get(root, path.slice('value.'.length));
3297
+ }
3298
+ if (path === 'context' || path.startsWith('context.')) {
3299
+ return path === 'context' ? context : get(context, path.slice('context.'.length));
3300
+ }
3301
+ if (path.startsWith('./') || path.startsWith('../') || path === '.' || path === '..') {
3302
+ let upCount = 0;
3303
+ let rest = path;
3304
+ let consumed = true;
3305
+ while (consumed) {
3306
+ consumed = false;
3307
+ if (rest.startsWith('../')) {
3308
+ upCount++;
3309
+ rest = rest.slice(3);
3310
+ consumed = true;
3311
+ }
3312
+ else if (rest === '..') {
3313
+ upCount++;
3314
+ rest = '';
3315
+ }
3316
+ else if (rest.startsWith('./')) {
3317
+ rest = rest.slice(2);
3318
+ consumed = true;
3319
+ }
3320
+ else if (rest === '.') {
3321
+ rest = '';
3322
+ }
3323
+ }
3324
+ const scope = getModelChain(field)[upCount];
3325
+ return rest === '' ? scope : get(scope, rest);
3326
+ }
3327
+ return undefined;
3328
+ };
3329
+ const getRootModel = (field) => {
3330
+ let cur = field;
3331
+ while (cur.parent)
3332
+ cur = cur.parent;
3333
+ return cur.model;
3334
+ };
3335
+ const getModelChain = (field) => {
3336
+ const chain = [];
3337
+ let cur = field;
3338
+ let last = MODEL_CHAIN_SENTINEL;
3339
+ while (cur) {
3340
+ if (cur.model !== last) {
3341
+ chain.push(cur.model);
3342
+ last = cur.model;
3343
+ }
3344
+ cur = cur.parent;
3345
+ }
3346
+ return chain;
3347
+ };
3348
+ const MODEL_CHAIN_SENTINEL = Symbol('model-chain-sentinel');
3291
3349
 
3292
3350
  /*
3293
3351
  * Copyright (C) 2023 The Gravitee team (http://gravitee.io)
@@ -3331,8 +3389,6 @@ class GioFormJsonSchemaComponent {
3331
3389
  this.touched = false;
3332
3390
  this.isValid$ = new ReplaySubject(1); // Wait JsonSchema to be loaded to check if it's valid
3333
3391
  this.stateChanges$ = new Subject();
3334
- this.isWritingValue = false;
3335
- this.isStable = false;
3336
3392
  if (ngControl) {
3337
3393
  // Setting the value accessor directly (instead of using
3338
3394
  // the providers `NG_VALUE_ACCESSOR`) to avoid running into a circular import.
@@ -3379,9 +3435,9 @@ class GioFormJsonSchemaComponent {
3379
3435
  // Sync control value with default value (without emit event) as long as the component is not ready
3380
3436
  // When formly is initialised, it emits several values as it builds up step by step.
3381
3437
  this.formGroup.valueChanges
3382
- .pipe(distinctUntilChanged(isEqual), filter(() => this.isReady && !this.isWritingValue && this.isStable), tap(value => {
3438
+ .pipe(distinctUntilChanged(isEqual), tap(value => {
3383
3439
  this.ngControl?.control?.reset(value, { emitEvent: false });
3384
- }), takeUntil(this.unsubscribe$))
3440
+ }), takeUntil(this.ready), takeUntil(this.unsubscribe$))
3385
3441
  .subscribe();
3386
3442
  // Avoid ExpressionChangedAfterItHasBeenCheckedError on project
3387
3443
  this.changeDetectorRef.markForCheck();
@@ -3439,14 +3495,7 @@ class GioFormJsonSchemaComponent {
3439
3495
  }
3440
3496
  // From ControlValueAccessor
3441
3497
  writeValue(value) {
3442
- this.isWritingValue = true;
3443
- this.isStable = false;
3444
3498
  this.model = cloneDeep(value) ?? {};
3445
- setTimeout(() => {
3446
- this.isWritingValue = false;
3447
- this.isStable = true;
3448
- this.changeDetectorRef.markForCheck();
3449
- }, 0);
3450
3499
  }
3451
3500
  // From ControlValueAccessor
3452
3501
  registerOnChange(fn) {