@syncfusion/ej2-form-renderer 34.2.8 → 35.1.37

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.
Files changed (215) hide show
  1. package/dist/ej2-form-renderer.umd.min.js +2 -2
  2. package/dist/ej2-form-renderer.umd.min.js.map +1 -1
  3. package/dist/es6/ej2-form-renderer.es2015.js +3261 -1523
  4. package/dist/es6/ej2-form-renderer.es2015.js.map +1 -1
  5. package/dist/es6/ej2-form-renderer.es5.js +3316 -1540
  6. package/dist/es6/ej2-form-renderer.es5.js.map +1 -1
  7. package/dist/global/ej2-form-renderer.min.js +2 -2
  8. package/dist/global/ej2-form-renderer.min.js.map +1 -1
  9. package/dist/global/index.d.ts +1 -1
  10. package/package.json +11 -11
  11. package/src/{common → form-renderer/common}/checkbox-group.js +1 -1
  12. package/src/{common → form-renderer/common}/conditional-rule-engine.d.ts +1 -6
  13. package/src/{common → form-renderer/common}/custom-validation-engine.d.ts +1 -1
  14. package/src/{common → form-renderer/common}/expressions/expression-engine.d.ts +1 -4
  15. package/src/{common → form-renderer/common}/expressions/expression-parser.d.ts +1 -9
  16. package/src/{common → form-renderer/common}/index.d.ts +2 -0
  17. package/src/{common → form-renderer/common}/index.js +2 -0
  18. package/src/{common → form-renderer/common}/json-converter.d.ts +6 -1
  19. package/src/{common → form-renderer/common}/json-converter.js +49 -8
  20. package/src/form-renderer/common/props-forwarder.d.ts +38 -0
  21. package/src/form-renderer/common/props-forwarder.js +123 -0
  22. package/src/{common → form-renderer/common}/utils.d.ts +6 -0
  23. package/src/form-renderer/form-renderer/custom-widget-resolver.d.ts +17 -0
  24. package/src/form-renderer/form-renderer/custom-widget-resolver.js +39 -0
  25. package/src/form-renderer/form-renderer/form-renderer-model.d.ts +125 -0
  26. package/src/form-renderer/form-renderer/form-renderer.d.ts +373 -0
  27. package/src/form-renderer/{form-renderer.js → form-renderer/form-renderer.js} +419 -298
  28. package/src/form-renderer/form-renderer/index.d.ts +7 -0
  29. package/src/form-renderer/form-renderer/index.js +6 -0
  30. package/src/form-renderer/{render-form-field.js → form-renderer/render-form-field.js} +154 -25
  31. package/src/form-renderer/index.d.ts +3 -4
  32. package/src/form-renderer/index.js +3 -3
  33. package/src/index.d.ts +1 -4
  34. package/src/index.js +1 -4
  35. package/common.d.ts +0 -4
  36. package/common.js +0 -4
  37. package/src/form-renderer/form-renderer-model.d.ts +0 -65
  38. package/src/form-renderer/form-renderer.d.ts +0 -425
  39. package/styles/bds-lite.css +0 -599
  40. package/styles/bds-lite.scss +0 -2
  41. package/styles/bds.css +0 -599
  42. package/styles/bds.scss +0 -2
  43. package/styles/bootstrap-dark-lite.css +0 -608
  44. package/styles/bootstrap-dark-lite.scss +0 -2
  45. package/styles/bootstrap-dark.css +0 -608
  46. package/styles/bootstrap-dark.scss +0 -2
  47. package/styles/bootstrap-lite.css +0 -595
  48. package/styles/bootstrap-lite.scss +0 -2
  49. package/styles/bootstrap.css +0 -595
  50. package/styles/bootstrap.scss +0 -2
  51. package/styles/bootstrap4-lite.css +0 -595
  52. package/styles/bootstrap4-lite.scss +0 -2
  53. package/styles/bootstrap4.css +0 -595
  54. package/styles/bootstrap4.scss +0 -2
  55. package/styles/bootstrap5-dark-lite.css +0 -595
  56. package/styles/bootstrap5-dark-lite.scss +0 -2
  57. package/styles/bootstrap5-dark.css +0 -595
  58. package/styles/bootstrap5-dark.scss +0 -2
  59. package/styles/bootstrap5-lite.css +0 -595
  60. package/styles/bootstrap5-lite.scss +0 -2
  61. package/styles/bootstrap5.3-lite.css +0 -679
  62. package/styles/bootstrap5.3-lite.scss +0 -2
  63. package/styles/bootstrap5.3.css +0 -679
  64. package/styles/bootstrap5.3.scss +0 -2
  65. package/styles/bootstrap5.css +0 -595
  66. package/styles/bootstrap5.scss +0 -2
  67. package/styles/fabric-dark-lite.css +0 -608
  68. package/styles/fabric-dark-lite.scss +0 -2
  69. package/styles/fabric-dark.css +0 -608
  70. package/styles/fabric-dark.scss +0 -2
  71. package/styles/fabric-lite.css +0 -595
  72. package/styles/fabric-lite.scss +0 -2
  73. package/styles/fabric.css +0 -595
  74. package/styles/fabric.scss +0 -2
  75. package/styles/fluent-dark-lite.css +0 -595
  76. package/styles/fluent-dark-lite.scss +0 -2
  77. package/styles/fluent-dark.css +0 -595
  78. package/styles/fluent-dark.scss +0 -2
  79. package/styles/fluent-lite.css +0 -595
  80. package/styles/fluent-lite.scss +0 -2
  81. package/styles/fluent.css +0 -595
  82. package/styles/fluent.scss +0 -2
  83. package/styles/fluent2-lite.css +0 -681
  84. package/styles/fluent2-lite.scss +0 -2
  85. package/styles/fluent2.css +0 -681
  86. package/styles/fluent2.scss +0 -2
  87. package/styles/form-renderer/_all.scss +0 -2
  88. package/styles/form-renderer/_bds-definition.scss +0 -8
  89. package/styles/form-renderer/_bootstrap-dark-definition.scss +0 -8
  90. package/styles/form-renderer/_bootstrap-definition.scss +0 -8
  91. package/styles/form-renderer/_bootstrap4-definition.scss +0 -8
  92. package/styles/form-renderer/_bootstrap5-dark-definition.scss +0 -8
  93. package/styles/form-renderer/_bootstrap5-definition.scss +0 -8
  94. package/styles/form-renderer/_bootstrap5.3-definition.scss +0 -8
  95. package/styles/form-renderer/_fabric-dark-definition.scss +0 -8
  96. package/styles/form-renderer/_fabric-definition.scss +0 -8
  97. package/styles/form-renderer/_fluent-dark-definition.scss +0 -8
  98. package/styles/form-renderer/_fluent-definition.scss +0 -8
  99. package/styles/form-renderer/_fluent2-definition.scss +0 -8
  100. package/styles/form-renderer/_highcontrast-definition.scss +0 -8
  101. package/styles/form-renderer/_highcontrast-light-definition.scss +0 -8
  102. package/styles/form-renderer/_layout.scss +0 -480
  103. package/styles/form-renderer/_material-dark-definition.scss +0 -8
  104. package/styles/form-renderer/_material-definition.scss +0 -8
  105. package/styles/form-renderer/_material3-dark-definition.scss +0 -8
  106. package/styles/form-renderer/_material3-definition.scss +0 -8
  107. package/styles/form-renderer/_mixin.scss +0 -26
  108. package/styles/form-renderer/_tailwind-dark-definition.scss +0 -8
  109. package/styles/form-renderer/_tailwind-definition.scss +0 -8
  110. package/styles/form-renderer/_tailwind3-definition.scss +0 -8
  111. package/styles/form-renderer/_theme.scss +0 -69
  112. package/styles/form-renderer/_variables.scss +0 -2
  113. package/styles/form-renderer/bds.css +0 -599
  114. package/styles/form-renderer/bds.scss +0 -2
  115. package/styles/form-renderer/bootstrap-dark.css +0 -608
  116. package/styles/form-renderer/bootstrap-dark.scss +0 -2
  117. package/styles/form-renderer/bootstrap.css +0 -595
  118. package/styles/form-renderer/bootstrap.scss +0 -2
  119. package/styles/form-renderer/bootstrap4.css +0 -595
  120. package/styles/form-renderer/bootstrap4.scss +0 -2
  121. package/styles/form-renderer/bootstrap5-dark.css +0 -595
  122. package/styles/form-renderer/bootstrap5-dark.scss +0 -2
  123. package/styles/form-renderer/bootstrap5.3.css +0 -679
  124. package/styles/form-renderer/bootstrap5.3.scss +0 -2
  125. package/styles/form-renderer/bootstrap5.css +0 -595
  126. package/styles/form-renderer/bootstrap5.scss +0 -2
  127. package/styles/form-renderer/fabric-dark.css +0 -608
  128. package/styles/form-renderer/fabric-dark.scss +0 -2
  129. package/styles/form-renderer/fabric.css +0 -595
  130. package/styles/form-renderer/fabric.scss +0 -2
  131. package/styles/form-renderer/fluent-dark.css +0 -595
  132. package/styles/form-renderer/fluent-dark.scss +0 -2
  133. package/styles/form-renderer/fluent.css +0 -595
  134. package/styles/form-renderer/fluent.scss +0 -2
  135. package/styles/form-renderer/fluent2.css +0 -681
  136. package/styles/form-renderer/fluent2.scss +0 -2
  137. package/styles/form-renderer/highcontrast-light.css +0 -595
  138. package/styles/form-renderer/highcontrast-light.scss +0 -2
  139. package/styles/form-renderer/highcontrast.css +0 -608
  140. package/styles/form-renderer/highcontrast.scss +0 -2
  141. package/styles/form-renderer/material-dark.css +0 -608
  142. package/styles/form-renderer/material-dark.scss +0 -2
  143. package/styles/form-renderer/material.css +0 -595
  144. package/styles/form-renderer/material.scss +0 -2
  145. package/styles/form-renderer/material3-dark.css +0 -677
  146. package/styles/form-renderer/material3-dark.scss +0 -2
  147. package/styles/form-renderer/material3.css +0 -679
  148. package/styles/form-renderer/material3.scss +0 -2
  149. package/styles/form-renderer/tailwind-dark.css +0 -595
  150. package/styles/form-renderer/tailwind-dark.scss +0 -2
  151. package/styles/form-renderer/tailwind.css +0 -595
  152. package/styles/form-renderer/tailwind.scss +0 -2
  153. package/styles/form-renderer/tailwind3.css +0 -669
  154. package/styles/form-renderer/tailwind3.scss +0 -2
  155. package/styles/highcontrast-light-lite.css +0 -595
  156. package/styles/highcontrast-light-lite.scss +0 -2
  157. package/styles/highcontrast-light.css +0 -595
  158. package/styles/highcontrast-light.scss +0 -2
  159. package/styles/highcontrast-lite.css +0 -608
  160. package/styles/highcontrast-lite.scss +0 -2
  161. package/styles/highcontrast.css +0 -608
  162. package/styles/highcontrast.scss +0 -2
  163. package/styles/material-dark-lite.css +0 -608
  164. package/styles/material-dark-lite.scss +0 -2
  165. package/styles/material-dark.css +0 -608
  166. package/styles/material-dark.scss +0 -2
  167. package/styles/material-lite.css +0 -595
  168. package/styles/material-lite.scss +0 -2
  169. package/styles/material.css +0 -595
  170. package/styles/material.scss +0 -2
  171. package/styles/material3-dark-lite.css +0 -677
  172. package/styles/material3-dark-lite.scss +0 -2
  173. package/styles/material3-dark.css +0 -677
  174. package/styles/material3-dark.scss +0 -2
  175. package/styles/material3-lite.css +0 -679
  176. package/styles/material3-lite.scss +0 -2
  177. package/styles/material3.css +0 -679
  178. package/styles/material3.scss +0 -2
  179. package/styles/tailwind-dark-lite.css +0 -595
  180. package/styles/tailwind-dark-lite.scss +0 -2
  181. package/styles/tailwind-dark.css +0 -595
  182. package/styles/tailwind-dark.scss +0 -2
  183. package/styles/tailwind-lite.css +0 -595
  184. package/styles/tailwind-lite.scss +0 -2
  185. package/styles/tailwind.css +0 -595
  186. package/styles/tailwind.scss +0 -2
  187. package/styles/tailwind3-lite.css +0 -669
  188. package/styles/tailwind3-lite.scss +0 -2
  189. package/styles/tailwind3.css +0 -669
  190. package/styles/tailwind3.scss +0 -2
  191. /package/src/{common → form-renderer/common}/checkbox-group.d.ts +0 -0
  192. /package/src/{common → form-renderer/common}/conditional-rule-engine.js +0 -0
  193. /package/src/{common → form-renderer/common}/custom-validation-engine.js +0 -0
  194. /package/src/{common → form-renderer/common}/datagrid-component.d.ts +0 -0
  195. /package/src/{common → form-renderer/common}/datagrid-component.js +0 -0
  196. /package/src/{common → form-renderer/common}/expressions/dependency-tracker.d.ts +0 -0
  197. /package/src/{common → form-renderer/common}/expressions/dependency-tracker.js +0 -0
  198. /package/src/{common → form-renderer/common}/expressions/expression-engine.js +0 -0
  199. /package/src/{common → form-renderer/common}/expressions/expression-parser.js +0 -0
  200. /package/src/{common → form-renderer/common}/expressions/grid-expressions.d.ts +0 -0
  201. /package/src/{common → form-renderer/common}/expressions/grid-expressions.js +0 -0
  202. /package/src/{common → form-renderer/common}/expressions/index.d.ts +0 -0
  203. /package/src/{common → form-renderer/common}/expressions/index.js +0 -0
  204. /package/src/{common → form-renderer/common}/minmax-rule-engine.d.ts +0 -0
  205. /package/src/{common → form-renderer/common}/minmax-rule-engine.js +0 -0
  206. /package/src/{common → form-renderer/common}/option-fetcher.d.ts +0 -0
  207. /package/src/{common → form-renderer/common}/option-fetcher.js +0 -0
  208. /package/src/{common → form-renderer/common}/parser.d.ts +0 -0
  209. /package/src/{common → form-renderer/common}/parser.js +0 -0
  210. /package/src/{common → form-renderer/common}/static-html-renderer.d.ts +0 -0
  211. /package/src/{common → form-renderer/common}/static-html-renderer.js +0 -0
  212. /package/src/{common → form-renderer/common}/utils.js +0 -0
  213. /package/src/form-renderer/{render-form-field.d.ts → form-renderer/render-form-field.d.ts} +0 -0
  214. /package/src/form-renderer/{types → form-renderer/types}/form-schema.d.ts +0 -0
  215. /package/src/form-renderer/{types → form-renderer/types}/form-schema.js +0 -0
@@ -28,23 +28,22 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
28
28
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
29
29
  return c > 3 && r && Object.defineProperty(target, key, r), r;
30
30
  };
31
- import { Component, Property, Event, NotifyPropertyChanges, enableRipple, createElement, isNullOrUndefined, L10n, getComponent, addClass } from '@syncfusion/ej2-base';
31
+ import { Component, Collection, Property, Event, NotifyPropertyChanges, enableRipple, createElement, ChildProperty, isNullOrUndefined, L10n, getComponent, addClass, compile, SanitizeHtmlHelper } from '@syncfusion/ej2-base';
32
32
  import { Tab } from '@syncfusion/ej2-navigations';
33
33
  import { Tooltip } from '@syncfusion/ej2-popups';
34
34
  import { FormValidator } from '@syncfusion/ej2-inputs';
35
35
  import { renderFormField } from './render-form-field';
36
- import { mergeSchema } from '../common/json-converter';
36
+ import { resolveCustomWidget } from './custom-widget-resolver';
37
+ import { mergeSchema, inferTypeFromWidget } from '../common/json-converter';
37
38
  import { UniversalJsonParser } from '../common/parser';
38
39
  import { VALIDATION_REGEX, formatDateValues, splitWidths } from '../common/utils';
39
40
  import StaticHtmlRenderer from '../common/static-html-renderer';
40
- import { ConditionalRuleEngine } from '../common/conditional-rule-engine';
41
+ import { ConditionalRuleEngine } from '../common/index';
41
42
  import { ExpressionEngine } from '../common/expressions/expression-engine';
42
43
  import { MinMaxRuleEngine } from '../common/minmax-rule-engine';
43
44
  import { CustomValidationEngine } from '../common/custom-validation-engine';
44
45
  /**
45
46
  * @private
46
- *
47
- * Internal input target types array to define a target.
48
47
  */
49
48
  var inputTargetTypes = [
50
49
  'textbox',
@@ -68,6 +67,29 @@ var inputTargetTypes = [
68
67
  export var defaultLocale = {
69
68
  "unsupportedComponent": "Unsupported Component type"
70
69
  };
70
+ /**
71
+ * Specifies the custom widget settings for rendering custom templates for existing FormComponentTypes.
72
+ */
73
+ var CustomWidgetSetting = /** @class */ (function (_super) {
74
+ __extends(CustomWidgetSetting, _super);
75
+ function CustomWidgetSetting() {
76
+ return _super !== null && _super.apply(this, arguments) || this;
77
+ }
78
+ __decorate([
79
+ Property(null)
80
+ ], CustomWidgetSetting.prototype, "template", void 0);
81
+ __decorate([
82
+ Property('')
83
+ ], CustomWidgetSetting.prototype, "type", void 0);
84
+ __decorate([
85
+ Property('')
86
+ ], CustomWidgetSetting.prototype, "templateId", void 0);
87
+ __decorate([
88
+ Property('')
89
+ ], CustomWidgetSetting.prototype, "fieldName", void 0);
90
+ return CustomWidgetSetting;
91
+ }(ChildProperty));
92
+ export { CustomWidgetSetting };
71
93
  /**
72
94
  * The FormRenderer component consumes a JSON form schema and renders a fully functional, Syncfusion-based form. It handles field mapping, conditional visibility/disabling, expression evaluation, custom validation, and data submission.
73
95
  *
@@ -82,131 +104,57 @@ export var defaultLocale = {
82
104
  var FormRenderer = /** @class */ (function (_super) {
83
105
  __extends(FormRenderer, _super);
84
106
  /**
85
- * Constructor for creating the widget
86
- *
87
- * @param {FormRendererModel} options - Specifies the form renderer model
88
- * @param {string|HTMLDivElement} element - Specifies the target element
107
+ * @private
89
108
  */
90
109
  function FormRenderer(options, element) {
91
110
  var _this = _super.call(this, options, element) || this;
92
111
  _this.processedSchemaCache = { version: '1.0.0', components: [] };
93
- /** Localization instance */
94
112
  _this.l10n = new L10n('form-renderer', defaultLocale, _this.locale);
95
113
  /**
96
114
  * @private
97
- *
98
- * Minimal form-state container owned by the orchestrator. The previous
99
- * vanilla-TS port delegated this to `FormStateBridge`; that bridge's
100
- * `registeredFields` gate silently short-circuited every field to "no
101
- * error" because the orchestrator never called `registerField`. The
102
- * EJ2 native `FormValidator` (bound to `this.element`) now handles all
103
- * rule evaluation, error-element placement, change/blur/submit wiring,
104
- * and ARIA — exactly what `FormValidator` was designed for. This object
105
- * is the orchestrator's authoritative values store; `errors` are
106
- * mirrored from the FormValidator's `errorRules` for `renderField`'s
107
- * initial-paint logic and for submit-time `isValid` checks.
108
115
  */
109
116
  _this.formState = { values: Object.create(null), errors: Object.create(null) };
110
- /** EJ2 native FormValidator bound to `this.element` (replaces FormStateBridge). */
111
117
  _this.validator = null;
112
- /** Map of input component instances keyed by `name` (or `${name}_${idx}`). */
113
118
  _this.inputRefs = {};
114
- /** Conditional value applied tracker (per-field). */
115
119
  _this.conditionalValueApplied = {};
116
- /** Expression engine + dependency graph + computed-field set. */
117
120
  _this.expressionEngine = null;
118
121
  _this.expressionDependencyGraph = {};
119
122
  _this.expressionEvaluationInProgress = false;
120
123
  _this.previousFormValues = {};
121
124
  _this.computedFieldNames = new Set();
122
- /** Custom validation engine instance. */
123
125
  _this.customValidationEngine = new CustomValidationEngine();
124
- /** Latest form values snapshot for custom validation (named-key context). */
125
126
  _this.currentFormValues = {};
126
- /** Whether initial values have been seeded once. */
127
127
  _this.isInitialized = false;
128
- /** Cached layout detection result. */
129
128
  _this.hasLayoutComponentsCache = false;
130
- /** Cached id→label map. */
131
129
  _this.idToLabelCache = {};
132
- /** Cached initial values (recomputed on schema change). */
133
130
  _this.initialValuesCache = {};
134
- /** Rendered child EJ2 instances (for destroy cleanup). */
135
131
  _this.renderedInstances = [];
136
- /** Tooltip instances keyed by field id so stale tooltips can be replaced promptly. */
137
132
  _this.tooltipRefs = {};
138
- /** `created` fired-once guard. */
139
133
  _this.createdFired = false;
140
- /**
141
- * Coalescing guard for `scheduleRerender`. Prevents redundant full-form
142
- * re-renders within a single microtask — mirrors React's batched-state
143
- * semantics so that a user keystroke + expression cascade fire one render.
144
- */
145
134
  _this.rerenderScheduled = false;
146
- /**
147
- * Set of `component.id`s that are referenced as the trigger field of any
148
- * other component's `conditions` (`visibleWhen` / `hideWhen` /
149
- * `disabledWhen` / `requiredWhen` / `readOnlyWhen` / `setValueWhen` /
150
- * `choiceBasedField.primaryFieldId`). Only changes to these fields can
151
- * affect visibility / disabled / required / valueWhen of any other
152
- * field, so only they need to trigger a full-form re-render. Changes to
153
- * fields *not* in this set are guaranteed to have no conditional side
154
- * effects and safely skip the (expensive) full DOM teardown + rebuild.
155
- * Built once per schema in `buildConditionalDependencyMap`.
156
- */
157
135
  _this.conditionalTriggerFieldIds = new Set();
158
- /**
159
- * Maps `component.id` → the previously-rendered DOM subtree (form-group)
160
- * for "expensive" components (dataGrid, dropdown, multiselect,
161
- * checkboxGroup) that support remote data. During a full-form re-render
162
- * triggered by an *unrelated* conditional change, these subtrees are
163
- * detached (not destroyed) and re-attached in place, avoiding a re-fetch
164
- * of their remote data sources and preventing the visible blink/reload.
165
- * A subtree is *invalidated* (dropped from this map, forcing a fresh
166
- * render) when a field it depends on (via its own `conditions` or
167
- * `conditionalData`) is the one that changed.
168
- */
169
136
  _this.preservedFields = new Map();
170
- /**
171
- * Per-consumer dependency map: `component.id` → set of trigger field ids
172
- * that the consumer's own `conditions` / `conditionalData` /
173
- * `choiceBasedField` reference. Used during `rerenderForm` to decide
174
- * whether a preserved subtree must be invalidated (rebuilt) because the
175
- * changed field is one of its own dependencies, or can be safely reused.
176
- */
177
137
  _this.consumerDependencyMap = new Map();
178
138
  /**
179
139
  * @private
180
- *
181
- * Coalesced full-form re-render. Multiple triggers within the same
182
- * microtask drain into a single `rerenderForm()` call. The set of
183
- * changed field ids is accumulated across the tick so `rerenderForm`
184
- * can decide which preserved subtrees must be invalidated (because one
185
- * of the changed fields is in their own dependency set).
186
140
  */
187
141
  _this.pendingChangedFieldIds = new Set();
188
142
  return _this;
189
143
  }
190
144
  FormRenderer_1 = FormRenderer;
191
145
  /**
192
- * Returns the EJ2 component module name.
193
146
  * @private
194
147
  */
195
148
  FormRenderer.prototype.getModuleName = function () {
196
149
  return 'form-renderer';
197
150
  };
198
151
  /**
199
- * Return the persisted-state payload. The base class declares this
200
- * abstract; FormRenderer does not implement state persistence, so an
201
- * empty object is returned (mirrors the EJ2 convention for
202
- * non-persistent components).
203
152
  * @private
204
153
  */
205
154
  FormRenderer.prototype.getPersistData = function () {
206
155
  return this.addOnPersist(['formState', JSON.stringify(this.formState)]);
207
156
  };
208
157
  /**
209
- * Pre-render wiring: enable ripple, init the expression engine + bridge.
210
158
  * @private
211
159
  */
212
160
  FormRenderer.prototype.preRender = function () {
@@ -215,7 +163,6 @@ var FormRenderer = /** @class */ (function (_super) {
215
163
  this.expressionEngine = new ExpressionEngine();
216
164
  };
217
165
  /**
218
- * Main render: normalize schema, build rules + initial values, render tree.
219
166
  * @private
220
167
  */
221
168
  FormRenderer.prototype.render = function () {
@@ -237,10 +184,12 @@ var FormRenderer = /** @class */ (function (_super) {
237
184
  this.idToLabelCache = this.computeIdToLabel();
238
185
  this.initialValuesCache = this.buildInitialValues();
239
186
  this.buildValidationRulesAndBridge();
240
- // Seed initial values into the form-state values map once.
241
187
  if (!this.isInitialized) {
242
188
  this.isInitialized = true;
243
189
  }
190
+ if (this.isReact && this.portals) {
191
+ this.renderReactTemplates();
192
+ }
244
193
  if (this.formState && this.initialValuesCache) {
245
194
  var initKeys = Object.keys(this.initialValuesCache);
246
195
  for (var _i = 0, initKeys_1 = initKeys; _i < initKeys_1.length; _i++) {
@@ -264,21 +213,7 @@ var FormRenderer = /** @class */ (function (_super) {
264
213
  var rendered = _this.renderComponent(component);
265
214
  if (rendered) {
266
215
  root.appendChild(rendered);
267
- }
268
- if (component.type === 'richTextEditor') {
269
- var rteElement = rendered.querySelector('.e-richtexteditor');
270
- var rteInstance = getComponent(rteElement, 'richtexteditor');
271
- rteInstance.refreshUI();
272
- }
273
- if (component.type === 'dataGrid') {
274
- var toolbarElement = rendered.querySelector('.e-control.e-toolbar');
275
- var rteInstance = getComponent(toolbarElement, 'toolbar');
276
- rteInstance.refresh();
277
- }
278
- if (component.type === 'tabs') {
279
- var tabElement = rendered.querySelector('.e-control.e-tab');
280
- var tabInstance = getComponent(tabElement, 'tab');
281
- tabInstance.refreshOverflow();
216
+ _this.refreshRenderedComponent(component, rendered);
282
217
  }
283
218
  });
284
219
  if (this.created && !this.createdFired) {
@@ -290,6 +225,58 @@ var FormRenderer = /** @class */ (function (_super) {
290
225
  }, 0);
291
226
  }
292
227
  };
228
+ FormRenderer.prototype.refreshRenderedComponent = function (component, rendered) {
229
+ var _this = this;
230
+ var componentRoot = rendered;
231
+ if (component.type === 'tabs') {
232
+ componentRoot = rendered.querySelector("#" + component.id + ".e-control.e-tab") || rendered;
233
+ }
234
+ else {
235
+ componentRoot = rendered.querySelector("[data-field-id=\"" + component.id + "\"]") || rendered;
236
+ }
237
+ if (component.type === 'richTextEditor') {
238
+ var rteElement = componentRoot.querySelector('.e-richtexteditor');
239
+ var rteInstance = rteElement ? getComponent(rteElement, 'richtexteditor') : null;
240
+ if (rteInstance) {
241
+ rteInstance.refreshUI();
242
+ }
243
+ }
244
+ else if (component.type === 'dataGrid') {
245
+ var toolbarElement = componentRoot.querySelector('.e-control.e-toolbar');
246
+ var toolbarInstance = toolbarElement ? getComponent(toolbarElement, 'toolbar') : null;
247
+ if (toolbarInstance) {
248
+ toolbarInstance.refresh();
249
+ }
250
+ }
251
+ else if (component.type === 'imageEditor') {
252
+ var editorElement = componentRoot.querySelector('.e-control.e-image-editor');
253
+ var editorInstance = editorElement ? getComponent(editorElement, 'image-editor') : null;
254
+ if (editorInstance) {
255
+ editorInstance.refresh();
256
+ }
257
+ }
258
+ else if (component.type === 'tabs') {
259
+ var tabInstance = getComponent(componentRoot, 'tab');
260
+ if (tabInstance) {
261
+ tabInstance.refreshOverflow();
262
+ }
263
+ }
264
+ if (component.children) {
265
+ component.children.forEach(function (child) { return _this.refreshRenderedComponent(child, rendered); });
266
+ }
267
+ if (component.tableCells) {
268
+ component.tableCells.forEach(function (row) {
269
+ row.forEach(function (cell) { return cell.forEach(function (child) { return _this.refreshRenderedComponent(child, rendered); }); });
270
+ });
271
+ }
272
+ if (component.tabItems) {
273
+ component.tabItems.forEach(function (tab) {
274
+ if (tab.content) {
275
+ tab.content.forEach(function (child) { return _this.refreshRenderedComponent(child, rendered); });
276
+ }
277
+ });
278
+ }
279
+ };
293
280
  /**
294
281
  * @private
295
282
  */
@@ -318,7 +305,7 @@ var FormRenderer = /** @class */ (function (_super) {
318
305
  var isUnifiedSchema = parsedInput && typeof parsedInput === 'object' &&
319
306
  parsedInput.properties && Array.isArray(parsedInput.layout);
320
307
  if (isUnifiedSchema) {
321
- this.processedSchemaCache = mergeSchema(parsedInput);
308
+ this.processedSchemaCache = mergeSchema(parsedInput, this.dataModel || undefined);
322
309
  }
323
310
  else {
324
311
  var parser = new UniversalJsonParser();
@@ -345,12 +332,7 @@ var FormRenderer = /** @class */ (function (_super) {
345
332
  this.processedSchemaCache = { version: '1.0.0', components: [] };
346
333
  }
347
334
  };
348
- // ----------------------------------------------------------------------
349
- // G3 — layout detection + suppression map
350
- // ----------------------------------------------------------------------
351
335
  /**
352
- * Recursively scan the schema for any `table`/`tabs`/`panel`/`card`
353
- * (including inside table cells and tab content). Mirrors `hasLayoutComponents`.
354
336
  * @private
355
337
  */
356
338
  FormRenderer.prototype.computeHasLayoutComponents = function () {
@@ -392,7 +374,6 @@ var FormRenderer = /** @class */ (function (_super) {
392
374
  };
393
375
  Object.defineProperty(FormRenderer.prototype, "layoutClass", {
394
376
  /**
395
- * The layout CSS class (suppressed when layout components are present).
396
377
  * @private
397
378
  */
398
379
  get: function () {
@@ -414,11 +395,7 @@ var FormRenderer = /** @class */ (function (_super) {
414
395
  enumerable: true,
415
396
  configurable: true
416
397
  });
417
- // ----------------------------------------------------------------------
418
- // G4 — collectAllComponents + idToLabel
419
- // ----------------------------------------------------------------------
420
398
  /**
421
- * Recursively collect all components including nested ones.
422
399
  * @private
423
400
  */
424
401
  FormRenderer.prototype.collectAllComponents = function (components) {
@@ -446,6 +423,22 @@ var FormRenderer = /** @class */ (function (_super) {
446
423
  traverse(components);
447
424
  return all;
448
425
  };
426
+ FormRenderer.prototype.getDataModelByName = function () {
427
+ var _this = this;
428
+ var dataModel = {};
429
+ var components = this.collectAllComponents(this.processedSchemaCache.components);
430
+ var componentsById = {};
431
+ components.forEach(function (component) {
432
+ componentsById[component.id] = component;
433
+ });
434
+ Object.keys(this.formState.values).forEach(function (id) {
435
+ var component = componentsById[id];
436
+ if (component && component.name) {
437
+ dataModel[component.name] = _this.formState.values[id];
438
+ }
439
+ });
440
+ return dataModel;
441
+ };
449
442
  /**
450
443
  * @private
451
444
  */
@@ -477,10 +470,6 @@ var FormRenderer = /** @class */ (function (_super) {
477
470
  traverse(this.processedSchemaCache.components);
478
471
  return map;
479
472
  };
480
- // ----------------------------------------------------------------------
481
- // G5 — buildValidationRules via FormStateBridge + ConditionalRuleEngine +
482
- // EMAIL/URL auto-regex + customValidator closure
483
- // ----------------------------------------------------------------------
484
473
  /**
485
474
  * @private
486
475
  */
@@ -597,13 +586,11 @@ var FormRenderer = /** @class */ (function (_super) {
597
586
  });
598
587
  };
599
588
  collectRules(this.processedSchemaCache.components);
600
- // Preserve previously-entered values across a re-render.
601
589
  var previousValues = this.formState ? __assign({}, this.formState.values) : __assign({}, this.initialValuesCache);
602
590
  this.formState = {
603
591
  values: Object.assign(Object.create(null), this.initialValuesCache, previousValues),
604
592
  errors: this.enablePersistence ? this.formState.errors : Object.create(null)
605
593
  };
606
- // Restore any previously-entered values that the merge above pruned.
607
594
  if (previousValues) {
608
595
  Object.keys(previousValues).forEach(function (id) {
609
596
  if (!(id in _this.formState.values)) {
@@ -611,7 +598,6 @@ var FormRenderer = /** @class */ (function (_super) {
611
598
  }
612
599
  });
613
600
  }
614
- // (Re)create the EJ2 native FormValidator bound to the host element.
615
601
  if (this.validator) {
616
602
  try {
617
603
  this.validator.refresh();
@@ -630,14 +616,6 @@ var FormRenderer = /** @class */ (function (_super) {
630
616
  errorElement: 'div',
631
617
  errorContainer: 'div',
632
618
  customPlacement: function (inputElement, errorElement) {
633
- // Locate the per-field error-message slot rendered in
634
- // `renderField` by its id (`error-<component.id>`). The
635
- // input's `name` attribute matches `component.id`
636
- // (set in renderField), so `getElementById('error-' + name)`
637
- // resolves the slot and the validator's error element is
638
- // appended into it (FormValidator sets
639
- // `errorElement.style.display = 'block'` before invoking
640
- // customPlacement, which makes the slot visible).
641
619
  var name = inputElement.getAttribute('name');
642
620
  if (!name) {
643
621
  if (inputElement.parentElement) {
@@ -658,15 +636,7 @@ var FormRenderer = /** @class */ (function (_super) {
658
636
  }
659
637
  },
660
638
  validationComplete: function (args) {
661
- // Mirror the validator's error state into formState.errors so
662
- // submit-time isValid and renderField's initial-paint logic
663
- // (which read formState.errors[id]) continue to work.
664
639
  self.syncFormStateErrors();
665
- // Keep the per-field error slot's visibility in sync with
666
- // the validator's outcome. On `success`, the FormValidator's
667
- // `hideMessage` sets its own error element's `display: none`,
668
- // but our slot (`error-<id>`) would otherwise keep the stale
669
- // error element appended. Clear + hide the slot on success.
670
640
  if (args && args.inputName) {
671
641
  var slot = document.getElementById("error-" + args.inputName);
672
642
  if (slot) {
@@ -701,10 +671,6 @@ var FormRenderer = /** @class */ (function (_super) {
701
671
  reset: function () {
702
672
  }
703
673
  });
704
- // Apply cached previous values to the FormValidator's input elements.
705
- // The validator reads live values from inputs at validate() time, but
706
- // initial values seeded here ensure any pre-populated values are
707
- // respected even if a field is never focused before submit.
708
674
  if (previousValues) {
709
675
  Object.keys(previousValues).forEach(function (id) {
710
676
  var inputEl = _this.validator.getInputElement(id);
@@ -719,10 +685,6 @@ var FormRenderer = /** @class */ (function (_super) {
719
685
  };
720
686
  /**
721
687
  * @private
722
- *
723
- * Mirror the FormValidator's `errorRules` array into `this.formState.errors`
724
- * keyed by field `name` (= `component.id`). Called after every
725
- * `validationComplete` callback and from submit-time `isValid` reads.
726
688
  */
727
689
  FormRenderer.prototype.syncFormStateErrors = function () {
728
690
  var errors = {};
@@ -779,11 +741,7 @@ var FormRenderer = /** @class */ (function (_super) {
779
741
  }
780
742
  return values;
781
743
  };
782
- // ----------------------------------------------------------------------
783
- // Expression engine init (used by G9)
784
- // ----------------------------------------------------------------------
785
744
  /**
786
- * Initialize the expression engine dependency graph + computed-field set.
787
745
  * @private
788
746
  */
789
747
  FormRenderer.prototype.initExpressionEngine = function () {
@@ -836,7 +794,7 @@ var FormRenderer = /** @class */ (function (_super) {
836
794
  var _this = this;
837
795
  var formState = this.formState;
838
796
  var formValues = formState ? formState.values : {};
839
- if (['panel', 'table', 'tabs', 'card', 'message', 'button', 'splitButton', 'staticHtml'].indexOf(component.type) !== -1) {
797
+ if (['panel', 'table', 'tabs', 'card', 'message', 'staticHtml'].indexOf(component.type) !== -1) {
840
798
  return null;
841
799
  }
842
800
  var conditionalReadOnly = ConditionalRuleEngine.isFieldReadOnly(component.conditions, formValues);
@@ -866,7 +824,6 @@ var FormRenderer = /** @class */ (function (_super) {
866
824
  var shouldShowError = !!(formState && formState.errors[component.id]);
867
825
  var isRequiredError = shouldShowError && !!(formState && formState.errors[component.id].indexOf('required') !== -1);
868
826
  var hasError = shouldShowError && !(isRequiredError && !computedRequired);
869
- // setValueWhen false→true transition tracking.
870
827
  var conditionIsActive = conditionalValue !== undefined;
871
828
  var wasConditionActive = this.conditionalValueApplied[component.id] || false;
872
829
  if (formState) {
@@ -969,7 +926,7 @@ var FormRenderer = /** @class */ (function (_super) {
969
926
  _this.formState.values[component.id] = value;
970
927
  formState.values[component.id] = value;
971
928
  }
972
- _this.trigger('change', { fieldName: component.name, label: component.label || component.id, value: value });
929
+ _this.trigger('change', { fieldName: component.name, label: component.label || component.id, value: value, dataModel: _this.getDataModelByName() });
973
930
  _this.afterValueChange(component.id);
974
931
  }
975
932
  };
@@ -991,60 +948,145 @@ var FormRenderer = /** @class */ (function (_super) {
991
948
  target.setAttribute('name', component.id);
992
949
  }
993
950
  fieldInput.appendChild(target);
994
- var instance = renderFormField({
995
- component: mergedComponent,
996
- value: formState ? formState.values[component.id] : undefined,
997
- onChange: onChangeHandler,
998
- formState: formState,
999
- settings: this.processedSchemaCache.settings,
1000
- onBlur: function () {
1001
- if (formState && component.type !== 'staticHtml') {
1002
- if (_this.validator) {
1003
- try {
1004
- _this.beforeValidate(component.id);
1005
- _this.validator.validate(component.id);
951
+ var skipDefault = false;
952
+ var resolvedWidget = resolveCustomWidget(component, this.customWidgetSettings);
953
+ if (resolvedWidget) {
954
+ var compiled = null;
955
+ try {
956
+ compiled = this.getTemplateFunction(resolvedWidget.entry.template);
957
+ }
958
+ catch (e) {
959
+ if (this.failure) {
960
+ this.trigger('failure', { error: e });
961
+ }
962
+ compiled = null;
963
+ }
964
+ if (compiled) {
965
+ try {
966
+ if (target.parentNode) {
967
+ target.parentNode.removeChild(target);
968
+ }
969
+ var swappedComponent = Object.assign({}, component, {
970
+ id: component.name,
971
+ name: component.id,
972
+ type: inferTypeFromWidget(component.type),
973
+ widget: component.type
974
+ });
975
+ var renderedOut = compiled({
976
+ fieldData: swappedComponent,
977
+ value: formState ? formState.values[component.id] : undefined,
978
+ }, this);
979
+ var outList = void 0;
980
+ if (renderedOut == null) {
981
+ outList = [];
982
+ }
983
+ else if (Array.isArray(renderedOut)) {
984
+ outList = renderedOut;
985
+ }
986
+ else if (typeof renderedOut === 'string') {
987
+ outList = [renderedOut];
988
+ }
989
+ else if (typeof renderedOut === 'object'
990
+ && !renderedOut.nodeType
991
+ && typeof renderedOut.length === 'number'
992
+ && typeof renderedOut.item === 'function') {
993
+ var snapshot = [];
994
+ var list = renderedOut;
995
+ for (var i = 0; i < list.length; i++) {
996
+ snapshot.push(list[i]);
1006
997
  }
1007
- catch (e) { /* swallow */ }
1008
- _this.syncFormStateErrors();
998
+ outList = snapshot;
1009
999
  }
1010
- }
1011
- },
1012
- ref: setInputRef,
1013
- hasError: hasError,
1014
- locale: this.locale,
1015
- components: this.collectAllComponents(this.processedSchemaCache.components),
1016
- enableRtl: this.enableRtl,
1017
- target: target,
1018
- l10n: this.l10n
1019
- });
1020
- if (Array.isArray(instance)) {
1021
- instance.forEach(function (entry) {
1022
- if (entry && typeof entry.destroy === 'function') {
1023
- _this.renderedInstances.push(entry);
1024
- }
1025
- else if (entry instanceof HTMLElement) {
1026
- for (var _i = 0, _a = Object.keys(_this.inputRefs); _i < _a.length; _i++) {
1027
- var key = _a[_i];
1028
- var inst = _this.inputRefs[key];
1029
- var hostEl = inst && (inst.element || inst.target || (inst.hostElement && inst.hostElement()));
1030
- if (hostEl && (hostEl === entry || entry.contains(hostEl))) {
1031
- _this.renderedInstances.push(inst);
1000
+ else {
1001
+ outList = [renderedOut];
1002
+ }
1003
+ for (var _i = 0, outList_1 = outList; _i < outList_1.length; _i++) {
1004
+ var node = outList_1[_i];
1005
+ if (node && typeof node === 'object' && node.nodeType) {
1006
+ fieldInput.appendChild(node);
1007
+ }
1008
+ else if (typeof node === 'string') {
1009
+ var markup = this.sanitizeTemplateValue(node);
1010
+ var span = createElement('span');
1011
+ span.innerHTML = markup;
1012
+ while (span.firstChild) {
1013
+ fieldInput.appendChild(span.firstChild);
1014
+ }
1015
+ }
1016
+ else if (node && typeof node === 'object') {
1017
+ throw new Error('Custom widget template for "' + component.name + '" returned a ' +
1018
+ 'framework object that the vanilla renderer cannot insert. Use the ' +
1019
+ 'React/Angular/Vue wrapper (registered templates / portals) for ' +
1020
+ 'JSX or platform templates.');
1032
1021
  }
1033
1022
  }
1023
+ setInputRef(fieldInput);
1024
+ skipDefault = true;
1034
1025
  }
1026
+ catch (renderErr) {
1027
+ if (this.failure) {
1028
+ this.trigger('failure', { error: renderErr });
1029
+ }
1030
+ skipDefault = false;
1031
+ }
1032
+ }
1033
+ }
1034
+ if (!skipDefault) {
1035
+ var instance = renderFormField({
1036
+ component: mergedComponent,
1037
+ value: formState ? formState.values[component.id] : undefined,
1038
+ onChange: onChangeHandler,
1039
+ formState: formState,
1040
+ settings: this.processedSchemaCache.settings,
1041
+ onBlur: function () {
1042
+ if (formState && component.type !== 'staticHtml') {
1043
+ if (_this.validator) {
1044
+ try {
1045
+ _this.beforeValidate(component.id);
1046
+ _this.validator.validate(component.id);
1047
+ }
1048
+ catch (e) { /* swallow */ }
1049
+ _this.syncFormStateErrors();
1050
+ }
1051
+ }
1052
+ },
1053
+ ref: setInputRef,
1054
+ hasError: hasError,
1055
+ locale: this.locale,
1056
+ components: this.collectAllComponents(this.processedSchemaCache.components),
1057
+ enableRtl: this.enableRtl,
1058
+ target: target,
1059
+ l10n: this.l10n
1035
1060
  });
1036
- }
1037
- else if (instance) {
1038
- if (typeof instance.destroy === 'function') {
1039
- this.renderedInstances.push(instance);
1040
- }
1041
- else if (instance instanceof HTMLElement) {
1042
- for (var _i = 0, _a = Object.keys(this.inputRefs); _i < _a.length; _i++) {
1043
- var key = _a[_i];
1044
- var inst = this.inputRefs[key];
1045
- var hostEl = inst && (inst.element || inst.target || (inst.hostElement && inst.hostElement()));
1046
- if (hostEl && (hostEl === instance || instance.contains(hostEl))) {
1047
- this.renderedInstances.push(inst);
1061
+ if (Array.isArray(instance)) {
1062
+ instance.forEach(function (entry) {
1063
+ if (entry && typeof entry.destroy === 'function') {
1064
+ _this.renderedInstances.push(entry);
1065
+ }
1066
+ else if (entry instanceof HTMLElement) {
1067
+ for (var _i = 0, _a = Object.keys(_this.inputRefs); _i < _a.length; _i++) {
1068
+ var key = _a[_i];
1069
+ var inst = _this.inputRefs[key];
1070
+ var hostEl = inst && (inst.element || inst.target || (inst.hostElement && inst.hostElement()));
1071
+ if (hostEl && (hostEl === entry || entry.contains(hostEl))) {
1072
+ _this.renderedInstances.push(inst);
1073
+ }
1074
+ }
1075
+ }
1076
+ });
1077
+ }
1078
+ else if (instance) {
1079
+ if (typeof instance.destroy === 'function') {
1080
+ this.renderedInstances.push(instance);
1081
+ }
1082
+ else if (instance instanceof HTMLElement) {
1083
+ for (var _a = 0, _b = Object.keys(this.inputRefs); _a < _b.length; _a++) {
1084
+ var key = _b[_a];
1085
+ var inst = this.inputRefs[key];
1086
+ var hostEl = inst && (inst.element || inst.target || (inst.hostElement && inst.hostElement()));
1087
+ if (hostEl && (hostEl === instance || instance.contains(hostEl))) {
1088
+ this.renderedInstances.push(inst);
1089
+ }
1048
1090
  }
1049
1091
  }
1050
1092
  }
@@ -1090,11 +1132,6 @@ var FormRenderer = /** @class */ (function (_super) {
1090
1132
  }
1091
1133
  return null;
1092
1134
  }
1093
- // Re-attach preserved subtree for expensive / remote-data components
1094
- // (dataGrid / dropdown / multiselect / checkboxGroup / lookup). The
1095
- // subtree was detached in `rerenderForm` before the rest of the tree
1096
- // was destroyed; re-attaching it here avoids a re-fetch of remote
1097
- // data sources and prevents the visible blink of a fresh render.
1098
1135
  if (FormRenderer_1.PRESERVABLE_TYPES.has(component.type) && this.preservedFields.has(component.id)) {
1099
1136
  var preservedNode = this.preservedFields.get(component.id);
1100
1137
  if (preservedNode) {
@@ -1191,14 +1228,6 @@ var FormRenderer = /** @class */ (function (_super) {
1191
1228
  tabHost.appendChild(tabHeader_1);
1192
1229
  tabHost.appendChild(tabContent_1);
1193
1230
  tabsDiv.appendChild(tabHost);
1194
- // Build the tab's host DOM up front so each `.e-content > .e-item`
1195
- // wrapper exists during initialization. Using the JSON `items`
1196
- // path causes EJ2 to lazily materialize only the active content
1197
- // panel, which leaves the remaining rendered tab bodies missing
1198
- // from the live DOM. By seeding the HTML markup structure and
1199
- // inserting the already-rendered live child nodes into every
1200
- // content item, the bound EJ2 instances stay attached and all
1201
- // tabs render correctly.
1202
1231
  (component.tabItems || []).forEach(function (tab) {
1203
1232
  var headerItem = createElement('div');
1204
1233
  headerItem.textContent = tab.header;
@@ -1308,6 +1337,9 @@ var FormRenderer = /** @class */ (function (_super) {
1308
1337
  return wrapper;
1309
1338
  }
1310
1339
  case 'button': {
1340
+ if (resolveCustomWidget(component, this.customWidgetSettings)) {
1341
+ return this.renderField(component);
1342
+ }
1311
1343
  var buttonlDisabled = ConditionalRuleEngine.isFieldDisabled(component.conditions, formValues);
1312
1344
  var buttonComputed = !!component.disabled || buttonlDisabled;
1313
1345
  var wrapper = createElement('div', { className: 'form-group' });
@@ -1369,6 +1401,9 @@ var FormRenderer = /** @class */ (function (_super) {
1369
1401
  return wrapper;
1370
1402
  }
1371
1403
  case 'splitButton': {
1404
+ if (resolveCustomWidget(component, this.customWidgetSettings)) {
1405
+ return this.renderField(component);
1406
+ }
1372
1407
  var splitButtonDisabled = ConditionalRuleEngine.isFieldDisabled(component.conditions, formValues);
1373
1408
  var computedDisabled = !!component.disabled || splitButtonDisabled;
1374
1409
  var wrapper = createElement('div', { className: 'form-group' });
@@ -1422,11 +1457,6 @@ var FormRenderer = /** @class */ (function (_super) {
1422
1457
  this.beforeValidate(changedFieldId);
1423
1458
  this.validator.validate(changedFieldId);
1424
1459
  this.syncFormStateErrors();
1425
- // Only schedule a full-form re-render when the changed field is a
1426
- // conditional trigger (i.e. some other field's visibility/disabled/
1427
- // required/readOnly/valueWhen references its id). Changes to fields
1428
- // that nothing depends on skip the expensive DOM teardown + rebuild,
1429
- // keeping keystroke latency low for non-conditional inputs.
1430
1460
  if (changedFieldId && this.isConditionalTrigger(changedFieldId)) {
1431
1461
  this.scheduleRerender(changedFieldId);
1432
1462
  }
@@ -1440,6 +1470,9 @@ var FormRenderer = /** @class */ (function (_super) {
1440
1470
  infoElement.classList.remove('e-error');
1441
1471
  }
1442
1472
  var inputElement = this.getInputElementByName(fieldId);
1473
+ if (!inputElement) {
1474
+ return;
1475
+ }
1443
1476
  var inputParent = inputElement.parentElement;
1444
1477
  var grandParent = inputParent.parentElement;
1445
1478
  if (inputParent.classList.contains('e-control-wrapper') || inputParent.classList.contains('e-wrapper') ||
@@ -1474,23 +1507,15 @@ var FormRenderer = /** @class */ (function (_super) {
1474
1507
  };
1475
1508
  /**
1476
1509
  * @private
1477
- *
1478
- * Recursively walk a `ConditionType` (a `ConditionalRule { field }` leaf
1479
- * or a `CompositeConditionalRule { rules: [...] }` tree) and collect the
1480
- * `field` ids of every leaf rule into the supplied `acc` set. These are
1481
- * the trigger ids whose value changes can affect the visibility/disabled/
1482
- * required/readOnly/valueWhen of the component that owns this `conditions`.
1483
1510
  */
1484
1511
  FormRenderer.prototype.collectConditionFieldIds = function (condition, acc) {
1485
1512
  if (!condition) {
1486
1513
  return;
1487
1514
  }
1488
1515
  if (typeof condition.field === 'string') {
1489
- // Leaf rule.
1490
1516
  acc.add(condition.field);
1491
1517
  }
1492
1518
  else if (Array.isArray(condition.rules)) {
1493
- // Composite (and/or) — recurse.
1494
1519
  for (var _i = 0, _a = condition.rules; _i < _a.length; _i++) {
1495
1520
  var sub = _a[_i];
1496
1521
  this.collectConditionFieldIds(sub, acc);
@@ -1519,18 +1544,9 @@ var FormRenderer = /** @class */ (function (_super) {
1519
1544
  };
1520
1545
  /**
1521
1546
  * @private
1522
- *
1523
- * Build `this.conditionalTriggerFieldIds` — the set of every
1524
- * `component.id` that is referenced by *any* other component's
1525
- * `conditions` (visibleWhen / hideWhen / disabledWhen / requiredWhen /
1526
- * readOnlyWhen / setValueWhen / choiceBasedField.primaryFieldId).
1527
- * Only changes to ids in this set can affect another field's
1528
- * visibility/enabled/required/value, so only they need to trigger a
1529
- * full-form re-render. Called once per schema during `render()`.
1530
1547
  */
1531
1548
  FormRenderer.prototype.buildConditionalDependencyMap = function () {
1532
1549
  var triggers = new Set();
1533
- // Per-consumer dependency set (rebuilt each pass).
1534
1550
  var consumerDeps = new Map();
1535
1551
  var allComps = this.collectAllComponents(this.processedSchemaCache.components);
1536
1552
  var _loop_3 = function (comp) {
@@ -1561,7 +1577,6 @@ var FormRenderer = /** @class */ (function (_super) {
1561
1577
  this_1.collectConditionFieldIds(item.condition, triggers);
1562
1578
  this_1.collectConditionFieldIds(item.condition, myDeps);
1563
1579
  }
1564
- // DataGrid conditional columns
1565
1580
  if (item && Array.isArray(item.conditions)) {
1566
1581
  for (var _c = 0, _d = item.conditions; _c < _d.length; _c++) {
1567
1582
  var subCond = _d[_c];
@@ -1609,13 +1624,6 @@ var FormRenderer = /** @class */ (function (_super) {
1609
1624
  collectMinMaxReferenceIds(range);
1610
1625
  }
1611
1626
  }
1612
- // ==========================================================
1613
- // DataGrid remote datasource dependencies
1614
- // Example:
1615
- // search.key = "{combobox}"
1616
- // filter.value = "{department}"
1617
- // Resolve component by NAME and add its ID as dependency.
1618
- // ==========================================================
1619
1627
  var ds = comp.dataSource;
1620
1628
  if ((comp.type === 'dataGrid') &&
1621
1629
  ds &&
@@ -1645,26 +1653,29 @@ var FormRenderer = /** @class */ (function (_super) {
1645
1653
  };
1646
1654
  /**
1647
1655
  * @private
1648
- *
1649
- * Returns `true` if a value change to `fieldId` can affect any other
1650
- * field's conditional state (visibility/disabled/required/readOnly/
1651
- * valueWhen/choiceBasedField) — i.e. `fieldId` is in the
1652
- * `conditionalTriggerFieldIds` set built by
1653
- * `buildConditionalDependencyMap`. Used by `afterValueChange` to skip
1654
- * the expensive full-form re-render when the changed field is not a
1655
- * conditional trigger.
1656
1656
  */
1657
1657
  FormRenderer.prototype.isConditionalTrigger = function (fieldId) {
1658
1658
  return this.conditionalTriggerFieldIds.has(fieldId);
1659
1659
  };
1660
+ FormRenderer.prototype.getScrollParent = function () {
1661
+ var parent = this.element.parentElement;
1662
+ while (parent) {
1663
+ var style = window.getComputedStyle(parent);
1664
+ var overflowY = style.overflowY;
1665
+ var overflowX = style.overflowX;
1666
+ var canScrollY = (overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay') &&
1667
+ parent.scrollHeight > parent.clientHeight;
1668
+ var canScrollX = (overflowX === 'auto' || overflowX === 'scroll' || overflowX === 'overlay') &&
1669
+ parent.scrollWidth > parent.clientWidth;
1670
+ if (canScrollY || canScrollX) {
1671
+ return parent;
1672
+ }
1673
+ parent = parent.parentElement;
1674
+ }
1675
+ return null;
1676
+ };
1660
1677
  /**
1661
1678
  * @private
1662
- *
1663
- * Tear down the rendered tree and re-render it, preserving user-entered
1664
- * `formState.values` (carried through `buildValidationRulesAndBridge`'s
1665
- * `previousValues` merge) and restoring keyboard focus to the field that
1666
- * had it before re-render (so a user typing in a textbox is not
1667
- * interrupted by a dependent field appearing/disappearing on the page).
1668
1679
  */
1669
1680
  FormRenderer.prototype.rerenderForm = function (changedFieldIds) {
1670
1681
  var _this = this;
@@ -1680,12 +1691,15 @@ var FormRenderer = /** @class */ (function (_super) {
1680
1691
  selectionStart = activeEl.selectionStart;
1681
1692
  selectionEnd = activeEl.selectionEnd;
1682
1693
  }
1683
- catch (e) { /* not a text input — ignore */ }
1694
+ catch (e) { /* ignore */ }
1684
1695
  }
1685
1696
  var savedElementScrollTop = this.element.scrollTop;
1686
1697
  var savedElementScrollLeft = this.element.scrollLeft;
1687
1698
  var savedWindowScrollX = window.scrollX;
1688
1699
  var savedWindowScrollY = window.scrollY;
1700
+ var scrollParent = this.getScrollParent();
1701
+ var savedScrollParentTop = scrollParent ? scrollParent.scrollTop : 0;
1702
+ var savedScrollParentLeft = scrollParent ? scrollParent.scrollLeft : 0;
1689
1703
  this.preservedFields.clear();
1690
1704
  var allComps = this.collectAllComponents(this.processedSchemaCache.components);
1691
1705
  var _loop_4 = function (comp) {
@@ -1716,6 +1730,9 @@ var FormRenderer = /** @class */ (function (_super) {
1716
1730
  _loop_4(comp);
1717
1731
  }
1718
1732
  this.refreshing = true;
1733
+ if (this.isReact || this.isAngular) {
1734
+ this.clearTemplate();
1735
+ }
1719
1736
  this.destroyRenderedExcludingPreserved();
1720
1737
  this.removePreviousRoot();
1721
1738
  if (this.validator) {
@@ -1726,6 +1743,10 @@ var FormRenderer = /** @class */ (function (_super) {
1726
1743
  try {
1727
1744
  this.element.scrollTop = savedElementScrollTop;
1728
1745
  this.element.scrollLeft = savedElementScrollLeft;
1746
+ if (scrollParent) {
1747
+ scrollParent.scrollTop = savedScrollParentTop;
1748
+ scrollParent.scrollLeft = savedScrollParentLeft;
1749
+ }
1729
1750
  window.scrollTo(savedWindowScrollX, savedWindowScrollY);
1730
1751
  }
1731
1752
  catch (e) { /* swallow */ }
@@ -1745,15 +1766,9 @@ var FormRenderer = /** @class */ (function (_super) {
1745
1766
  catch (e) { /* swallow */ }
1746
1767
  }
1747
1768
  }
1748
- // Drop preserved subtrees that were not re-attached (e.g. their
1749
- // field became hidden during this re-render). Their EJ2 instances
1750
- // are still in `renderedInstances`; destroy them now to avoid leaks.
1751
1769
  if (this.preservedFields.size > 0) {
1752
1770
  var stillKept_1 = [];
1753
1771
  this.preservedFields.forEach(function (node, id) {
1754
- // If the node is no longer in the live document tree, the
1755
- // field was not re-attached (hidden / removed). Destroy it
1756
- // and remove the detached DOM node so it cannot be re-used.
1757
1772
  if (!_this.element.contains(node) && !document.body.contains(node)) {
1758
1773
  _this.destroyPreservedSubtree(node);
1759
1774
  try {
@@ -1762,7 +1777,7 @@ var FormRenderer = /** @class */ (function (_super) {
1762
1777
  }
1763
1778
  }
1764
1779
  catch (e) {
1765
- // swallow
1780
+ // ignore
1766
1781
  }
1767
1782
  _this.preservedFields.delete(id);
1768
1783
  }
@@ -1816,11 +1831,6 @@ var FormRenderer = /** @class */ (function (_super) {
1816
1831
  };
1817
1832
  /**
1818
1833
  * @private
1819
- *
1820
- * Destroy all rendered EJ2 instances except those whose host element
1821
- * lives inside a preserved subtree (those are kept alive for re-use in
1822
- * the upcoming `render()` pass). Mirrors `destroyRendered` but skips
1823
- * instances rooted in `preservedFields` nodes.
1824
1834
  */
1825
1835
  FormRenderer.prototype.destroyRenderedExcludingPreserved = function () {
1826
1836
  var survived = [];
@@ -1841,8 +1851,6 @@ var FormRenderer = /** @class */ (function (_super) {
1841
1851
  _loop_5(inst);
1842
1852
  }
1843
1853
  this.renderedInstances = survived;
1844
- // Prune inputRefs whose host element lives in a destroyed subtree
1845
- // (preserved ones stay).
1846
1854
  var inputRefKeys = Object.keys(this.inputRefs);
1847
1855
  var _loop_6 = function (key) {
1848
1856
  var inst = this_4.inputRefs[key];
@@ -1865,10 +1873,6 @@ var FormRenderer = /** @class */ (function (_super) {
1865
1873
  };
1866
1874
  /**
1867
1875
  * @private
1868
- *
1869
- * Destroy EJ2 instances whose host element lives inside a preserved
1870
- * subtree that was NOT re-attached (field became hidden). Used during
1871
- * the post-render cleanup pass in `rerenderForm`.
1872
1876
  */
1873
1877
  FormRenderer.prototype.destroyPreservedSubtree = function (rootNode) {
1874
1878
  var survived = [];
@@ -1898,7 +1902,6 @@ var FormRenderer = /** @class */ (function (_super) {
1898
1902
  return inputEl;
1899
1903
  };
1900
1904
  /**
1901
- * Evaluate expressions in topological order with type coercion.
1902
1905
  * @private
1903
1906
  */
1904
1907
  FormRenderer.prototype.evaluateExpressions = function () {
@@ -1999,22 +2002,10 @@ var FormRenderer = /** @class */ (function (_super) {
1999
2002
  }
2000
2003
  if (result !== null && result !== undefined && result !== formValues[component.id] && this_5.formState) {
2001
2004
  this_5.formState.values[component.id] = result;
2002
- // Sync the underlying input element so the
2003
- // FormValidator reads the new value on its
2004
- // next validate() pass.
2005
2005
  if (this_5.validator) {
2006
2006
  var inputEl = this_5.getInputElementByName(component.id);
2007
2007
  if (inputEl) {
2008
- try {
2009
- if (inputEl.ej2_instances[0]) {
2010
- inputEl.ej2_instances[0].value = result;
2011
- // (inputEl as any).ej2_instances[0].refresh();
2012
- }
2013
- else {
2014
- (inputEl).value = String(result);
2015
- }
2016
- }
2017
- catch (e) { /* swallow */ }
2008
+ this_5.syncValueToInput(inputEl, component.id, result);
2018
2009
  }
2019
2010
  }
2020
2011
  }
@@ -2041,7 +2032,6 @@ var FormRenderer = /** @class */ (function (_super) {
2041
2032
  }
2042
2033
  };
2043
2034
  /**
2044
- * Re-trigger custom validation for changed + dependent fields.
2045
2035
  * @private
2046
2036
  */
2047
2037
  FormRenderer.prototype.retriggerCustomValidation = function () {
@@ -2146,13 +2136,106 @@ var FormRenderer = /** @class */ (function (_super) {
2146
2136
  }
2147
2137
  };
2148
2138
  /**
2149
- * Retrieves the underlying Syncfusion form-input component instance by its field name. Use this to call Syncfusion component methods and properties.
2139
+ * Retrieves the underlying Syncfusion form-input component instance by its field name.
2140
+ * Use this to call Syncfusion component methods and properties.
2141
+ *
2142
+ * @param {string} name - Specifies the name for the built-in Syncfusion component.
2143
+ * @returns {object | null} - Specifies the instance of the Syncfusion component in the form.
2150
2144
  */
2151
2145
  FormRenderer.prototype.getComponent = function (name) {
2152
2146
  return this.inputRefs[name] || null;
2153
2147
  };
2154
2148
  /**
2155
- * Re-normalize + re-render on `schema`/`locale`/`enableRtl` change.
2149
+ * Programmatically sets a form field's value for user edits.
2150
+ *
2151
+ * @param {string} fieldName - The field's `name` (the schema property's `name`).
2152
+ * @param {any} value - The new value to set.
2153
+ * @returns void
2154
+ */
2155
+ FormRenderer.prototype.setFieldValue = function (fieldName, value) {
2156
+ var allComponents = this.collectAllComponents(this.processedSchemaCache.components || []);
2157
+ var component = allComponents.find(function (c) { return c.name === fieldName; });
2158
+ if (!component) {
2159
+ return;
2160
+ }
2161
+ if (this.formState) {
2162
+ this.formState.values[component.id] = value;
2163
+ }
2164
+ var inputEl = this.getInputElementByName(component.id);
2165
+ if (inputEl) {
2166
+ this.syncValueToInput(inputEl, component.id, value);
2167
+ }
2168
+ this.afterValueChange(component.id);
2169
+ };
2170
+ /**
2171
+ * @private
2172
+ */
2173
+ FormRenderer.prototype.syncValueToInput = function (inputEl, fieldId, value) {
2174
+ if (!inputEl) {
2175
+ return;
2176
+ }
2177
+ try {
2178
+ var nativeInput = (inputEl instanceof HTMLInputElement) ? inputEl : null;
2179
+ var isCheckable = !!nativeInput &&
2180
+ (nativeInput.type === 'checkbox' || nativeInput.type === 'radio');
2181
+ var ej2Inst = inputEl.ej2_instances && inputEl.ej2_instances[0];
2182
+ if (ej2Inst) {
2183
+ if (isCheckable && typeof ej2Inst.checked !== 'undefined') {
2184
+ if (nativeInput.type === 'radio' && typeof ej2Inst.value !== 'undefined') {
2185
+ ej2Inst.checked = String(value) === String(ej2Inst.value);
2186
+ }
2187
+ else {
2188
+ ej2Inst.checked = FormRenderer_1.coerceChecked(value);
2189
+ }
2190
+ }
2191
+ else if (typeof ej2Inst.value !== 'undefined') {
2192
+ ej2Inst.value = value;
2193
+ }
2194
+ return;
2195
+ }
2196
+ if (inputEl instanceof HTMLSelectElement) {
2197
+ var strValue = (value === null || value === undefined) ? '' : String(value);
2198
+ inputEl.value = strValue;
2199
+ if (inputEl.value !== strValue && inputEl.options.length > 0) {
2200
+ for (var i = 0; i < inputEl.options.length; i++) {
2201
+ if (inputEl.options[i].text === strValue) {
2202
+ inputEl.value = inputEl.options[i].value;
2203
+ break;
2204
+ }
2205
+ }
2206
+ }
2207
+ }
2208
+ else if (nativeInput && nativeInput.type === 'radio') {
2209
+ var radios = this.element.querySelectorAll("input[type=\"radio\"][name=\"" + fieldId + "\"]");
2210
+ for (var i = 0; i < radios.length; i++) {
2211
+ radios[i].checked = String(value) === radios[i].value;
2212
+ }
2213
+ }
2214
+ else if (isCheckable) {
2215
+ nativeInput.checked = FormRenderer_1.coerceChecked(value);
2216
+ }
2217
+ else if (typeof inputEl.value !== 'undefined') {
2218
+ inputEl.value = (value === null || value === undefined) ? '' : String(value);
2219
+ }
2220
+ }
2221
+ catch (e) { /* ignore */ }
2222
+ };
2223
+ /**
2224
+ * @private
2225
+ */
2226
+ FormRenderer.coerceChecked = function (value) {
2227
+ if (typeof value === 'boolean') {
2228
+ return value;
2229
+ }
2230
+ if (typeof value === 'number') {
2231
+ return value !== 0;
2232
+ }
2233
+ if (typeof value === 'string') {
2234
+ return value !== '' && value !== 'false' && value !== '0';
2235
+ }
2236
+ return !!value;
2237
+ };
2238
+ /**
2156
2239
  * @private
2157
2240
  */
2158
2241
  FormRenderer.prototype.onPropertyChanged = function (newProps, oldProps) {
@@ -2160,6 +2243,9 @@ var FormRenderer = /** @class */ (function (_super) {
2160
2243
  if (newProps.schema !== oldProps.schema) {
2161
2244
  reRender = true;
2162
2245
  }
2246
+ if (newProps.dataModel !== oldProps.dataModel) {
2247
+ reRender = true;
2248
+ }
2163
2249
  if (newProps.locale !== oldProps.locale) {
2164
2250
  reRender = true;
2165
2251
  }
@@ -2169,13 +2255,15 @@ var FormRenderer = /** @class */ (function (_super) {
2169
2255
  if (newProps.layout !== oldProps.layout) {
2170
2256
  reRender = true;
2171
2257
  }
2172
- if (newProps.locale !== oldProps.locale) {
2258
+ if (newProps.customWidgetSettings !== oldProps.customWidgetSettings) {
2173
2259
  reRender = true;
2174
2260
  }
2175
2261
  if (!reRender) {
2176
2262
  return;
2177
2263
  }
2178
- // Tear down rendered children and re-render.
2264
+ if (this.isReact || this.isAngular) {
2265
+ this.clearTemplate();
2266
+ }
2179
2267
  this.refreshing = true;
2180
2268
  this.destroyRendered();
2181
2269
  this.removePreviousRoot();
@@ -2184,7 +2272,6 @@ var FormRenderer = /** @class */ (function (_super) {
2184
2272
  this.refreshing = false;
2185
2273
  };
2186
2274
  /**
2187
- * Destroy all child EJ2 instances, detach listeners, null refs.
2188
2275
  * @private
2189
2276
  */
2190
2277
  FormRenderer.prototype.destroyRendered = function () {
@@ -2217,7 +2304,6 @@ var FormRenderer = /** @class */ (function (_super) {
2217
2304
  this.pendingChangedFieldIds = new Set();
2218
2305
  };
2219
2306
  /**
2220
- * Remove persisted tab selection state for this form when it is fully destroyed.
2221
2307
  * @private
2222
2308
  */
2223
2309
  FormRenderer.prototype.clearPersistedTabSelections = function () {
@@ -2237,11 +2323,43 @@ var FormRenderer = /** @class */ (function (_super) {
2237
2323
  catch (_a) {
2238
2324
  }
2239
2325
  };
2326
+ FormRenderer.prototype.getTemplateFunction = function (template) {
2327
+ var templateFn = null;
2328
+ try {
2329
+ if (typeof template === 'string' && template.indexOf('#') !== -1 && document.querySelectorAll(template).length) {
2330
+ templateFn = compile(this.sanitizeTemplateValue(document.querySelector(template).innerHTML.trim()));
2331
+ }
2332
+ else if (typeof template === 'string') {
2333
+ templateFn = compile(this.sanitizeTemplateValue(template));
2334
+ }
2335
+ else {
2336
+ templateFn = compile(template);
2337
+ }
2338
+ }
2339
+ catch (e) {
2340
+ templateFn = compile(template);
2341
+ }
2342
+ return templateFn;
2343
+ };
2344
+ /**
2345
+ * @private
2346
+ */
2347
+ FormRenderer.prototype.sanitizeTemplateValue = function (value) {
2348
+ if (this.enableHtmlSanitizer && typeof value === 'string') {
2349
+ try {
2350
+ return SanitizeHtmlHelper.sanitize(value);
2351
+ }
2352
+ catch (e) { /* swallow */ }
2353
+ }
2354
+ return value;
2355
+ };
2240
2356
  /**
2241
- * Full component teardown.
2242
2357
  * @private
2243
2358
  */
2244
2359
  FormRenderer.prototype.destroy = function () {
2360
+ if (this.isReact || this.isAngular) {
2361
+ this.clearTemplate();
2362
+ }
2245
2363
  this.destroyRendered();
2246
2364
  this.formState = { values: {}, errors: {} };
2247
2365
  this.expressionEngine = null;
@@ -2274,24 +2392,27 @@ var FormRenderer = /** @class */ (function (_super) {
2274
2392
  }
2275
2393
  };
2276
2394
  var FormRenderer_1;
2277
- /**
2278
- * Component types eligible for DOM preservation across re-renders.
2279
- * These types either bind remote data (dataGrid, lookup-backed
2280
- * dropdown/multiselect) or render many child options (checkboxGroup)
2281
- * and are noticeably expensive / flicker-prone to rebuild.
2282
- */
2283
2395
  FormRenderer.PRESERVABLE_TYPES = new Set([
2284
2396
  'textbox', 'textarea', 'number', 'checkbox', 'checkboxGroup', 'radio', 'dropdown', 'multiselect', 'button', 'date', 'dateTime', 'time', 'dateRange', 'switch', 'signature', 'rating', 'imageEditor', 'fileUpload', 'rangeSlider', 'colorPicker', 'inputMask', 'message', 'panel', 'table', 'tabs', 'dataGrid', 'staticHtml', 'card', 'splitButton', 'richTextEditor'
2285
2397
  ]);
2286
2398
  __decorate([
2287
2399
  Property(null)
2288
2400
  ], FormRenderer.prototype, "schema", void 0);
2401
+ __decorate([
2402
+ Property(null)
2403
+ ], FormRenderer.prototype, "dataModel", void 0);
2289
2404
  __decorate([
2290
2405
  Property('SingleColumn')
2291
2406
  ], FormRenderer.prototype, "layout", void 0);
2292
2407
  __decorate([
2293
2408
  Property('')
2294
2409
  ], FormRenderer.prototype, "className", void 0);
2410
+ __decorate([
2411
+ Collection([], CustomWidgetSetting)
2412
+ ], FormRenderer.prototype, "customWidgetSettings", void 0);
2413
+ __decorate([
2414
+ Property(false)
2415
+ ], FormRenderer.prototype, "enableHtmlSanitizer", void 0);
2295
2416
  __decorate([
2296
2417
  Event()
2297
2418
  ], FormRenderer.prototype, "submit", void 0);