@ngx-formly/core 11.0.0 → 11.1.0-rc.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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
|
-
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentRef, ContentChildren, DOCUMENT, DestroyRef, Directive, EventEmitter, Inject, Injectable, InjectionToken, Injector, Input, NgModule, Optional, Output, PendingTasks, Pipe, TemplateRef, Type, VERSION, ViewChild, ViewChildren, ViewContainerRef, inject, ɵNoopNgZone } from "@angular/core";
|
|
2
|
+
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentRef, ContentChildren, DOCUMENT, DestroyRef, Directive, EventEmitter, Inject, Injectable, InjectionToken, Injector, Input, NgModule, Optional, Output, PendingTasks, Pipe, TemplateRef, Type, VERSION, ViewChild, ViewChildren, ViewContainerRef, effect, inject, isWritableSignal, untracked, ɵNoopNgZone } from "@angular/core";
|
|
3
3
|
import { Observable, Subject, Subscription, combineLatest, isObservable, merge, of } from "rxjs";
|
|
4
4
|
import * as i2$1 from "@angular/forms";
|
|
5
5
|
import { AbstractControl, FormControl, NgControl, UntypedFormArray, UntypedFormControl, UntypedFormGroup, Validators } from "@angular/forms";
|
|
@@ -116,13 +116,16 @@ function isObject(x) {
|
|
|
116
116
|
function isPromise(obj) {
|
|
117
117
|
return !!obj && typeof obj.then === "function";
|
|
118
118
|
}
|
|
119
|
-
function
|
|
120
|
-
|
|
119
|
+
function isKeptByReference(value) {
|
|
120
|
+
return !isObject(value) || isObservable(value) || isPromise(value) || value instanceof TemplateRef || value.changingThisBreaksApplicationSecurity || [
|
|
121
121
|
"RegExp",
|
|
122
122
|
"FileList",
|
|
123
123
|
"File",
|
|
124
124
|
"Blob"
|
|
125
|
-
].indexOf(value.constructor?.name) !== -1
|
|
125
|
+
].indexOf(value.constructor?.name) !== -1;
|
|
126
|
+
}
|
|
127
|
+
function clone(value) {
|
|
128
|
+
if (isKeptByReference(value)) return value;
|
|
126
129
|
if (value instanceof Set) return new Set(value);
|
|
127
130
|
if (value instanceof Map) return new Map(value);
|
|
128
131
|
if (value instanceof Uint8Array) return new Uint8Array(value);
|
|
@@ -142,6 +145,15 @@ function clone(value) {
|
|
|
142
145
|
return newVal;
|
|
143
146
|
}, c);
|
|
144
147
|
}
|
|
148
|
+
function isEqualValue(a, b) {
|
|
149
|
+
if (Object.is(a, b)) return true;
|
|
150
|
+
if (isKeptByReference(a) || isKeptByReference(b) || Object.getPrototypeOf(a) !== Object.getPrototypeOf(b)) return false;
|
|
151
|
+
if (a instanceof Date) return Object.is(a.getTime(), b.getTime());
|
|
152
|
+
if (a instanceof Map) return a.size === b.size && [...a].every(([k, v]) => b.has(k) && isEqualValue(v, b.get(k)));
|
|
153
|
+
if (a instanceof Set) return a.size === b.size && [...a].every((v) => b.has(v));
|
|
154
|
+
const keys = Object.keys(a);
|
|
155
|
+
return keys.length === Object.keys(b).length && keys.every((k) => Object.prototype.hasOwnProperty.call(b, k) && isEqualValue(a[k], b[k]));
|
|
156
|
+
}
|
|
145
157
|
function defineHiddenProp(field, prop, defaultValue) {
|
|
146
158
|
Object.defineProperty(field, prop, {
|
|
147
159
|
enumerable: false,
|
|
@@ -2378,6 +2390,7 @@ var FormlyFormBuilder = class FormlyFormBuilder {
|
|
|
2378
2390
|
subscription?.unsubscribe();
|
|
2379
2391
|
}
|
|
2380
2392
|
if (firstBuild && lastEmittedStatus !== field.form.status) field.form.statusChanges.emit(field.form.status);
|
|
2393
|
+
if (!controlsForCheck) options._afterBuild?.forEach((afterBuild) => afterBuild());
|
|
2381
2394
|
}
|
|
2382
2395
|
_build(field) {
|
|
2383
2396
|
if (!field) return;
|
|
@@ -2477,6 +2490,12 @@ var FormlyForm = class FormlyForm {
|
|
|
2477
2490
|
return this.field.form;
|
|
2478
2491
|
}
|
|
2479
2492
|
set model(model) {
|
|
2493
|
+
this.modelSignalEffect?.destroy();
|
|
2494
|
+
this.modelSignal = void 0;
|
|
2495
|
+
if (isWritableSignal(model)) {
|
|
2496
|
+
this.bindModelSignal(model);
|
|
2497
|
+
return;
|
|
2498
|
+
}
|
|
2480
2499
|
if (this.config.extras.immutable && this._modelChangeValue === model) return;
|
|
2481
2500
|
this.setField({ model });
|
|
2482
2501
|
}
|
|
@@ -2490,6 +2509,7 @@ var FormlyForm = class FormlyForm {
|
|
|
2490
2509
|
return this.field.fieldGroup;
|
|
2491
2510
|
}
|
|
2492
2511
|
set options(options) {
|
|
2512
|
+
this.field.options?._afterBuild?.delete(this.afterBuild);
|
|
2493
2513
|
this.setField({ options });
|
|
2494
2514
|
}
|
|
2495
2515
|
get options() {
|
|
@@ -2508,19 +2528,19 @@ var FormlyForm = class FormlyForm {
|
|
|
2508
2528
|
this.field = { type: "formly-group" };
|
|
2509
2529
|
this.destroyRef = inject(DestroyRef);
|
|
2510
2530
|
this.pendingTasks = inject(PendingTasks);
|
|
2531
|
+
this.injector = inject(Injector);
|
|
2511
2532
|
this._modelChangeValue = {};
|
|
2512
2533
|
this.valueChangesUnsubscribe = () => {};
|
|
2534
|
+
this.afterBuild = () => {
|
|
2535
|
+
if (this.modelSignal) this.syncModelSignal(this.modelSignal);
|
|
2536
|
+
};
|
|
2513
2537
|
}
|
|
2514
2538
|
ngDoCheck() {
|
|
2515
2539
|
if (this.config.extras.checkExpressionOn === "changeDetectionCheck") this.checkExpressionChange();
|
|
2516
2540
|
}
|
|
2517
2541
|
ngOnChanges(changes) {
|
|
2518
2542
|
if (changes.fields && this.form) clearControl(this.form);
|
|
2519
|
-
if (changes.fields || changes.form || changes.model && this._modelChangeValue !== changes.model.currentValue)
|
|
2520
|
-
this.valueChangesUnsubscribe();
|
|
2521
|
-
this.builder.build(this.field);
|
|
2522
|
-
this.valueChangesUnsubscribe = this.valueChanges();
|
|
2523
|
-
}
|
|
2543
|
+
if (changes.fields || changes.form || changes.model && this._modelChangeValue !== changes.model.currentValue) this.build();
|
|
2524
2544
|
if (changes.fields || changes.form) this.pendingTasks.run(async () => {
|
|
2525
2545
|
await Promise.resolve();
|
|
2526
2546
|
if (!this.destroyRef.destroyed) this.fieldChange.emit({
|
|
@@ -2533,6 +2553,7 @@ var FormlyForm = class FormlyForm {
|
|
|
2533
2553
|
ngOnDestroy() {
|
|
2534
2554
|
this.valueChangesUnsubscribe();
|
|
2535
2555
|
this.config.clearRefs();
|
|
2556
|
+
this.field.options?._afterBuild?.delete(this.afterBuild);
|
|
2536
2557
|
}
|
|
2537
2558
|
checkExpressionChange() {
|
|
2538
2559
|
this.field.options.checkExpressions?.(this.field);
|
|
@@ -2550,9 +2571,13 @@ var FormlyForm = class FormlyForm {
|
|
|
2550
2571
|
});
|
|
2551
2572
|
}
|
|
2552
2573
|
const fieldChangesDetection = [observeDeep(this.field.options, ["formState"], () => this.field.options.detectChanges(this.field))];
|
|
2553
|
-
const valueChanges = this.field.options.fieldChanges.pipe(filter(({ field, type }) => hasKey(field) && type === "valueChanges"),
|
|
2574
|
+
const valueChanges = this.field.options.fieldChanges.pipe(filter(({ field, type }) => hasKey(field) && type === "valueChanges"), tap(() => {
|
|
2575
|
+
if (this.modelSignal) this.syncModelSignal(this.modelSignal);
|
|
2576
|
+
}), switchMap(() => isNoopNgZone(this.ngZone) ? of(null) : this.ngZone.onStable.asObservable().pipe(take(1)))).subscribe(() => this.ngZone.runGuarded(() => {
|
|
2554
2577
|
this.checkExpressionChange();
|
|
2555
|
-
this.
|
|
2578
|
+
this._modelChangeValue = clone(this.model);
|
|
2579
|
+
if (this.modelSignal) this.syncModelSignal(this.modelSignal, this._modelChangeValue);
|
|
2580
|
+
this.modelChange.emit(this._modelChangeValue);
|
|
2556
2581
|
}));
|
|
2557
2582
|
return () => {
|
|
2558
2583
|
fieldChangesDetection.forEach((fnc) => fnc());
|
|
@@ -2567,6 +2592,42 @@ var FormlyForm = class FormlyForm {
|
|
|
2567
2592
|
};
|
|
2568
2593
|
else Object.keys(field).forEach((p) => this.field[p] = field[p]);
|
|
2569
2594
|
}
|
|
2595
|
+
build() {
|
|
2596
|
+
this.valueChangesUnsubscribe();
|
|
2597
|
+
if (this.modelSignal) {
|
|
2598
|
+
const options = this.field.options ??= {};
|
|
2599
|
+
if (!options._afterBuild) defineHiddenProp(options, "_afterBuild", /* @__PURE__ */ new Set());
|
|
2600
|
+
options._afterBuild.add(this.afterBuild);
|
|
2601
|
+
}
|
|
2602
|
+
this.builder.build(this.field);
|
|
2603
|
+
this.valueChangesUnsubscribe = this.valueChanges();
|
|
2604
|
+
}
|
|
2605
|
+
bindModelSignal(model) {
|
|
2606
|
+
this.modelSignal = model;
|
|
2607
|
+
this.modelSignalValue = model();
|
|
2608
|
+
this.useSignalValue(this.modelSignalValue);
|
|
2609
|
+
this.modelSignalEffect = effect(() => {
|
|
2610
|
+
const value = model();
|
|
2611
|
+
if (value === this.modelSignalValue) return;
|
|
2612
|
+
this.modelSignalValue = value;
|
|
2613
|
+
untracked(() => {
|
|
2614
|
+
this.useSignalValue(value);
|
|
2615
|
+
this.build();
|
|
2616
|
+
});
|
|
2617
|
+
}, {
|
|
2618
|
+
...ngDevMode ? { debugName: "modelSignalEffect" } : /* istanbul ignore next */ {},
|
|
2619
|
+
injector: this.injector
|
|
2620
|
+
});
|
|
2621
|
+
}
|
|
2622
|
+
syncModelSignal(modelSignal, copy) {
|
|
2623
|
+
const current = untracked(modelSignal);
|
|
2624
|
+
if (current !== this.modelSignalValue || isEqualValue(this.model, current ?? {})) return;
|
|
2625
|
+
modelSignal.set(copy ?? clone(this.model));
|
|
2626
|
+
this.modelSignalValue = untracked(modelSignal);
|
|
2627
|
+
}
|
|
2628
|
+
useSignalValue(model) {
|
|
2629
|
+
this.setField({ model: this.config.extras.immutable ? model : clone(model) });
|
|
2630
|
+
}
|
|
2570
2631
|
static {
|
|
2571
2632
|
this.ɵfac = i0.ɵɵngDeclareFactory({
|
|
2572
2633
|
minVersion: "12.0.0",
|