@jinntec/fore 1.3.0 → 1.5.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.
Files changed (44) hide show
  1. package/dist/fore-dev.js +8 -8
  2. package/dist/fore-dev.js.map +1 -1
  3. package/dist/fore.js +7 -7
  4. package/dist/fore.js.map +1 -1
  5. package/index.js +1 -0
  6. package/package.json +1 -1
  7. package/resources/fore.css +6 -1
  8. package/src/ForeElementMixin.js +4 -0
  9. package/src/actions/abstract-action.js +117 -48
  10. package/src/actions/fx-action.js +9 -9
  11. package/src/actions/fx-append.js +1 -1
  12. package/src/actions/fx-confirm.js +1 -1
  13. package/src/actions/fx-copy.js +68 -0
  14. package/src/actions/fx-delete.js +1 -1
  15. package/src/actions/fx-dispatch.js +1 -1
  16. package/src/actions/fx-hide.js +1 -1
  17. package/src/actions/fx-insert.js +1 -1
  18. package/src/actions/fx-message.js +1 -1
  19. package/src/actions/fx-refresh.js +2 -2
  20. package/src/actions/fx-reload.js +1 -1
  21. package/src/actions/fx-replace.js +1 -1
  22. package/src/actions/fx-return.js +1 -1
  23. package/src/actions/fx-send.js +2 -2
  24. package/src/actions/fx-setfocus.js +1 -1
  25. package/src/actions/fx-setvalue.js +1 -1
  26. package/src/actions/fx-show.js +1 -1
  27. package/src/actions/fx-toggle.js +1 -1
  28. package/src/actions/fx-update.js +1 -1
  29. package/src/fore.js +59 -10
  30. package/src/fx-bind.js +5 -0
  31. package/src/fx-fore.js +92 -35
  32. package/src/fx-instance.js +70 -70
  33. package/src/fx-model.js +12 -17
  34. package/src/fx-submission.js +420 -416
  35. package/src/getInScopeContext.js +19 -5
  36. package/src/modelitem.js +3 -1
  37. package/src/ui/abstract-control.js +1 -1
  38. package/src/ui/fx-control.js +2 -2
  39. package/src/ui/fx-repeat-attributes.js +442 -0
  40. package/src/ui/fx-repeat.js +8 -0
  41. package/src/ui/fx-switch.js +9 -1
  42. package/src/ui/fx-trigger.js +19 -18
  43. package/src/xpath-evaluation.js +21 -9
  44. package/src/xpath-util.js +13 -28
package/src/fore.js CHANGED
@@ -9,6 +9,16 @@ export class Fore {
9
9
 
10
10
  static TYPE_DEFAULT = 'xs:string';
11
11
 
12
+ /**
13
+ * returns the next `fx-fore` element upwards in tree
14
+ *
15
+ * @param start
16
+ * @returns {*}
17
+ */
18
+ static getFore(start) {
19
+ return start.nodeType === Node.TEXT_NODE ? start.parentNode.closest('fx-fore'):start.closest('fx-fore');
20
+ }
21
+
12
22
  static get ACTION_ELEMENTS() {
13
23
  return [
14
24
  'FX-ACTION',
@@ -76,6 +86,7 @@ export class Fore {
76
86
  'FX-RANGE',
77
87
  'FX-REPEAT',
78
88
  'FX-REPEATITEM',
89
+ 'FX-REPEAT-ATTRIBUTES',
79
90
  'FX-SWITCH',
80
91
  'FX-SECRET',
81
92
  'FX-SELECT',
@@ -285,14 +296,23 @@ export class Fore {
285
296
  return fadeOut();
286
297
  }
287
298
 
288
- static dispatch(target, eventName, detail) {
299
+ static async dispatch(target, eventName, detail) {
289
300
  const event = new CustomEvent(eventName, {
290
301
  composed: false,
291
302
  bubbles: true,
292
303
  detail,
293
304
  });
294
- console.info('dispatching', event.type, target);
295
- target.dispatchEvent(event);
305
+ event.listenerPromises = [];
306
+ // console.info('dispatching', event.type, target);
307
+ // console.log('!!! DISPATCH_START', eventName);
308
+
309
+ target.dispatchEvent(event);
310
+
311
+ // By now, all listeners for the event should have registered their completion promises to us.
312
+ if (event.listenerPromises.length) {
313
+ await Promise.all(event.listenerPromises);
314
+ }
315
+ // console.log('!!! DISPATCH_DONE', eventName);
296
316
  }
297
317
 
298
318
  static prettifyXml(source) {
@@ -409,13 +429,42 @@ export class Fore {
409
429
  }),
410
430
  );
411
431
  }
412
- hostElement.appendChild(theFore);
413
- theFore.classList.add('widget');
414
- // return theFore;
415
- // theFore.setAttribute('from-src', this.src);
416
- // this.replaceWith(theFore);
432
+ const imported = document.importNode(theFore,true);
433
+ console.log(`########## loaded fore as component ##### ${hostElement.url}`);
434
+ imported.addEventListener(
435
+ 'model-construct-done',
436
+ e => {
437
+ console.log('subcomponent ready', e.target);
438
+ const defaultInst = imported.querySelector('fx-instance');
439
+ // console.log('defaultInst', defaultInst);
440
+ if(hostElement.initialNode){
441
+ const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
442
+ // Note: Clone the input to prevent the inner fore from editing the outer node
443
+ doc.firstElementChild.appendChild(hostElement.initialNode.cloneNode(true));
444
+ // defaultinst.setInstanceData(this.initialNode);
445
+ defaultInst.setInstanceData(doc);
446
+ }
447
+ // console.log('new data', defaultInst.getInstanceData());
448
+ // theFore.getModel().modelConstruct();
449
+ imported.getModel().updateModel();
450
+ imported.refresh();
451
+ return 'done';
452
+
453
+ },
454
+ { once: true },
455
+ );
456
+
457
+ const dummy = hostElement.querySelector('input');
458
+ if (hostElement.hasAttribute('shadow')) {
459
+ dummy.parentNode.removeChild(dummy);
460
+ hostElement.shadowRoot.appendChild(imported);
461
+ } else {
462
+ console.log(this, 'replacing widget with',theFore);
463
+ dummy.replaceWith(imported);
464
+ // this.appendChild(imported);
465
+ }
417
466
  })
418
- .catch(error => {
467
+ /*.catch(error => {
419
468
  hostElement.dispatchEvent(
420
469
  new CustomEvent('error', {
421
470
  composed: false,
@@ -426,7 +475,7 @@ export class Fore {
426
475
  },
427
476
  }),
428
477
  );
429
- });
478
+ });*/
430
479
  }
431
480
 
432
481
  /**
package/src/fx-bind.js CHANGED
@@ -320,6 +320,11 @@ export class FxBind extends foreElementMixin(HTMLElement) {
320
320
  this,
321
321
  );
322
322
 
323
+ const alert = this.getAlert();
324
+ if (alert) {
325
+ newItem.addAlert(alert);
326
+ }
327
+
323
328
  this.getModel().registerModelItem(newItem);
324
329
  }
325
330
 
package/src/fx-fore.js CHANGED
@@ -5,7 +5,8 @@ import '@jinntec/jinn-toast';
5
5
  import {evaluateXPathToBoolean, evaluateXPathToNodes, evaluateXPathToString} from './xpath-evaluation.js';
6
6
  import getInScopeContext from './getInScopeContext.js';
7
7
  import {XPathUtil} from './xpath-util.js';
8
- import {AbstractAction} from "./actions/abstract-action";
8
+ // import {FxRepeat} from "./ui/fx-repeat";
9
+ import {FxRepeatAttributes} from './ui/fx-repeat-attributes.js';
9
10
 
10
11
  /**
11
12
  * Main class for Fore.Outermost container element for each Fore application.
@@ -15,9 +16,9 @@ import {AbstractAction} from "./actions/abstract-action";
15
16
  * fx-fore is the outermost container for each form. A form can have exactly one model
16
17
  * with arbitrary number of instances.
17
18
  *
18
- * Main responsiblities are initialization and updating of model and instances, update of UI (refresh) and global messaging.
19
+ * Main responsibilities are initialization and updating of model and instances, update of UI (refresh) and global messaging.
19
20
  *
20
- * @event compute-exception - dispatched in case the dependency graph is cirular
21
+ * @event compute-exception - dispatched in case the dependency graph is circular
21
22
  * @event refresh-done - dispatched after a refresh() run
22
23
  * @event ready - dispatched after Fore has fully been initialized
23
24
  * @event error - dispatches error when template expression fails to evaluate
@@ -56,7 +57,7 @@ export class FxFore extends HTMLElement {
56
57
  constructor() {
57
58
  super();
58
59
  this.model = {};
59
- this.addEventListener('model-construct-done', this._handleModelConstructDone);
60
+ // this.addEventListener('model-construct-done', this._handleModelConstructDone);
60
61
  this.addEventListener('message', this._displayMessage);
61
62
  this.addEventListener('error', this._displayError);
62
63
  window.addEventListener('compute-exception', e => {
@@ -68,19 +69,11 @@ export class FxFore extends HTMLElement {
68
69
 
69
70
  const style = `
70
71
  :host {
71
- // display: none;
72
- height:auto;
73
- padding:var(--model-element-padding);
74
- font-family:Roboto, sans-serif;
75
- color:var(--paper-grey-900);
72
+ display: block;
76
73
  }
77
74
  :host ::slotted(fx-model){
78
75
  display:none;
79
76
  }
80
- // :host(.fx-ready){
81
- // animation: fadein .4s forwards;
82
- // display:block;
83
- // }
84
77
 
85
78
  #modalMessage .dialogActions{
86
79
  text-align:center;
@@ -144,14 +137,6 @@ export class FxFore extends HTMLElement {
144
137
  #messageContent{
145
138
  margin-top:40px;
146
139
  }
147
- @keyframes fadein {
148
- 0% {
149
- opacity:0;
150
- }
151
- 100% {
152
- opacity:1;
153
- }
154
- }
155
140
  `;
156
141
 
157
142
  const html = `
@@ -179,11 +164,12 @@ export class FxFore extends HTMLElement {
179
164
  this.toRefresh = [];
180
165
  this.initialRun = true;
181
166
  this.someInstanceDataStructureChanged = false;
167
+ this.repeatsFromAttributesCreated = false;
182
168
  }
183
169
 
184
170
  connectedCallback() {
185
171
  this.style.visibility = 'hidden';
186
-
172
+ console.time('init');
187
173
  /*
188
174
  document.addEventListener('ready', (e) =>{
189
175
  if(e.target !== this){
@@ -220,7 +206,7 @@ export class FxFore extends HTMLElement {
220
206
  }
221
207
 
222
208
  const slot = this.shadowRoot.querySelector('slot');
223
- slot.addEventListener('slotchange', event => {
209
+ slot.addEventListener('slotchange', async event => {
224
210
 
225
211
  // preliminary addition for auto-conversion of non-prefixed element into prefixed elements. See fore.js
226
212
  if(this.hasAttribute('convert')){
@@ -239,19 +225,23 @@ export class FxFore extends HTMLElement {
239
225
  modelElement = generatedModel;
240
226
  }
241
227
  if (!modelElement.inited) {
242
- console.info(
243
- `%cFore is processing URL ${window.location.href}`,
244
- "background:#64b5f6; color:white; padding:1rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;",
245
- );
228
+ console.info(
229
+ `%cFore is processing URL ${window.location.href}`,
230
+ "background:#64b5f6; color:white; padding:1rem; display:inline-block; white-space: nowrap; border-radius:0.3rem;width:100%;",
231
+ );
246
232
 
247
233
  if (this.src) {
248
234
  console.log('########## FORE: loaded from ... ', this.src, '##########');
249
235
  }
250
- modelElement.modelConstruct();
236
+ await modelElement.modelConstruct();
237
+ this._handleModelConstructDone();
251
238
  }
252
239
  this.model = modelElement;
240
+
241
+ this._createRepeatsFromAttributes();
242
+
253
243
  });
254
- this.addEventListener('path-mutated', e => {
244
+ this.addEventListener('path-mutated', () => {
255
245
  // console.log('path-mutated event received', e.detail.path, e.detail.index);
256
246
  this.someInstanceDataStructureChanged = true;
257
247
  });
@@ -300,7 +290,7 @@ export class FxFore extends HTMLElement {
300
290
 
301
291
  // console.log('thefore', theFore)
302
292
  if (!theFore) {
303
- Fore.dispatchEvent(this, 'error', {
293
+ Fore.dispatch(this, 'error', {
304
294
  detail: {
305
295
  message: `Fore element not found in '${this.src}'. Maybe wrapped within 'template' element?`,
306
296
  },
@@ -324,9 +314,13 @@ export class FxFore extends HTMLElement {
324
314
  */
325
315
  handleIntersect(entries, observer) {
326
316
  console.time('refreshLazy');
317
+
327
318
  entries.forEach(entry => {
328
319
  const {target} = entry;
329
320
 
321
+ const fore = Fore.getFore(target);
322
+ if(fore.initialRun) return;
323
+
330
324
  if (entry.isIntersecting) {
331
325
  console.log('in view', entry);
332
326
  // console.log('repeat in view entry', entry.target);
@@ -497,7 +491,18 @@ export class FxFore extends HTMLElement {
497
491
  }
498
492
 
499
493
  _processTemplateExpressions() {
500
- for (const node of this.storedTemplateExpressionByNode.keys()) {
494
+ for (const node of Array.from(this.storedTemplateExpressionByNode.keys())) {
495
+ if (node.nodeType === Node.ATTRIBUTE_NODE) {
496
+ // Attribute nodes are not contained by the document, but their owner elements are!
497
+ if (!node.ownerDocument.contains(node.ownerElement)) {
498
+ this.storedTemplateExpressionByNode.delete(node);
499
+ continue;
500
+ }
501
+ } else if (!node.ownerDocument.contains(node)) {
502
+ // For all other nodes, if the document does not contain them, they are dead
503
+ this.storedTemplateExpressionByNode.delete(node);
504
+ continue;
505
+ }
501
506
  this._processTemplateExpression({
502
507
  node,
503
508
  expr: this.storedTemplateExpressionByNode.get(node),
@@ -512,7 +517,7 @@ export class FxFore extends HTMLElement {
512
517
  const {expr} = exprObj;
513
518
  const {node} = exprObj;
514
519
  // console.log('expr ', expr);
515
- this.evaluateTemplateExpression(expr, node, this);
520
+ this.evaluateTemplateExpression(expr, node);
516
521
  }
517
522
 
518
523
  /**
@@ -567,7 +572,7 @@ export class FxFore extends HTMLElement {
567
572
 
568
573
  /**
569
574
  * called when `model-construct-done` event is received to
570
- * start initing of the UI.
575
+ * start initing the UI.
571
576
  *
572
577
  * @private
573
578
  */
@@ -583,7 +588,7 @@ export class FxFore extends HTMLElement {
583
588
  && condition !== 'true'
584
589
  && condition !== ''){
585
590
  window.addEventListener('beforeunload', event => {
586
- const mustDisplay = evaluateXPathToBoolean(showConfirm, this.getModel().getDefaultContext(), this)
591
+ const mustDisplay = evaluateXPathToBoolean(condition, this.getModel().getDefaultContext(), this)
587
592
  if(mustDisplay){
588
593
  console.log('have to display confirmation')
589
594
  return event.returnValue = 'are you sure';
@@ -747,7 +752,8 @@ export class FxFore extends HTMLElement {
747
752
  };
748
753
  */
749
754
 
750
- await this.refresh();
755
+ // First refresh should be forced
756
+ await this.refresh(true);
751
757
  // this.style.display='block'
752
758
  this.classList.add('fx-ready');
753
759
  document.body.classList.add('fx-ready');
@@ -761,6 +767,7 @@ export class FxFore extends HTMLElement {
761
767
  `%cPage Initialization done`,
762
768
  "background:#64b5f6; color:white; padding:1rem; display:block; white-space: nowrap; border-radius:0.3rem;width:100%;",
763
769
  );
770
+ console.timeEnd('init');
764
771
  console.log('dataChanged', FxModel.dataChanged);
765
772
  }
766
773
 
@@ -817,6 +824,56 @@ export class FxFore extends HTMLElement {
817
824
  toast.showToast(msg);
818
825
  }
819
826
  }
827
+
828
+ /**
829
+ * wraps the element having a 'data-ref' attribute with an fx-repeat-attributes element.
830
+ * @private
831
+ */
832
+ _createRepeatsFromAttributes() {
833
+ if(this.repeatsFromAttributesCreated) return;
834
+ const repeats = this.querySelectorAll('[data-ref]');
835
+ if(repeats){
836
+ Array.from(repeats).forEach(item =>{
837
+
838
+ const table = item.parentNode.closest('table');
839
+ let host;
840
+ if(table){
841
+ host = table.cloneNode(true);
842
+ }else{
843
+ host = item.cloneNode(true);
844
+ }
845
+ // ### clone original item to move it into fx-repeat-attributes
846
+ // const host = item.cloneNode(true);
847
+
848
+ // ### create wrapper element
849
+ const repeatFromAttr = new FxRepeatAttributes();
850
+ // const repeatFromAttr = document.createElement('fx-repeat-attributes');
851
+
852
+ // ### copy the value of 'data-ref' to 'ref' on fx-repeat-attributes
853
+ repeatFromAttr.setAttribute('ref',item.getAttribute('data-ref'));
854
+ // item.removeAttribute('data-ref');
855
+
856
+ // ### append the cloned original element to fx-repeat-attributes
857
+ repeatFromAttr.appendChild(host);
858
+
859
+ // ### insert fx-repeat-attributes element before element with the 'data-ref'
860
+ // repeats[0].parentNode.insertBefore(repeatFromAttr,repeats[0]);
861
+
862
+ if(table){
863
+ table.parentNode.insertBefore(repeatFromAttr,table);
864
+ table.parentNode.removeChild(table);
865
+ }else{
866
+ item.parentNode.insertBefore(repeatFromAttr,item);
867
+ item.parentNode.removeChild(item);
868
+ }
869
+
870
+ // ### remove original item from DOM
871
+ item.setAttribute('insertPoint','');
872
+
873
+ });
874
+ }
875
+ this.repeatsFromAttributesCreated = true;
876
+ }
820
877
  }
821
878
 
822
879
  if (!customElements.get('fx-fore')) {
@@ -1,6 +1,43 @@
1
1
  import { Fore } from './fore.js';
2
2
  import { evaluateXPathToFirstNode } from './xpath-evaluation.js';
3
3
 
4
+ async function handleResponse(response) {
5
+ const { status } = response;
6
+ if (status >= 400) {
7
+ // console.log('response status', status);
8
+ alert(`response status: ${status} - failed to load data for '${this.src}' - stopping.`);
9
+ throw new Error(`failed to load data - status: ${status}`);
10
+ }
11
+ const responseContentType = response.headers.get('content-type').toLowerCase();
12
+ // console.log('********** responseContentType *********', responseContentType);
13
+ if (responseContentType.startsWith('text/html')) {
14
+ // const htmlResponse = response.text();
15
+ // return new DOMParser().parseFromString(htmlResponse, 'text/html');
16
+ // return response.text();
17
+ return response.text().then(result =>
18
+ // console.log('xml ********', result);
19
+ new DOMParser().parseFromString(result, 'text/html'),
20
+ );
21
+ }
22
+ if (
23
+ responseContentType.startsWith('text/plain') ||
24
+ responseContentType.startsWith('text/markdown')
25
+ ) {
26
+ // console.log("********** inside res plain *********");
27
+ return response.text();
28
+ }
29
+ if (responseContentType.startsWith('application/json')) {
30
+ // console.log("********** inside res json *********");
31
+ return response.json();
32
+ }
33
+ if (responseContentType.startsWith('application/xml')) {
34
+ const text = await response.text();
35
+ // console.log('xml ********', result);
36
+ return new DOMParser().parseFromString(text, 'application/xml');
37
+ }
38
+ return 'done';
39
+ }
40
+
4
41
  /**
5
42
  * Container for data instances.
6
43
  *
@@ -59,16 +96,15 @@ export class FxInstance extends HTMLElement {
59
96
  */
60
97
  async init() {
61
98
  // console.log('fx-instance init');
62
- await this._initInstance().then(() => {
63
- this.dispatchEvent(
64
- new CustomEvent('instance-loaded', {
65
- composed: true,
66
- bubbles: true,
67
- detail: { instance: this },
68
- }),
69
- );
70
- return this;
71
- });
99
+ await this._initInstance();
100
+ this.dispatchEvent(
101
+ new CustomEvent('instance-loaded', {
102
+ composed: true,
103
+ bubbles: true,
104
+ detail: { instance: this },
105
+ }),
106
+ );
107
+ return this;
72
108
  }
73
109
 
74
110
  evalXPath(xpath) {
@@ -155,22 +191,21 @@ export class FxInstance extends HTMLElement {
155
191
 
156
192
  async _loadData() {
157
193
  const url = `${this.src}`;
158
- const contentType = Fore.getContentType(this, 'get');
159
194
 
160
- if(url.startsWith('localStore')){
161
- const key = url.substring(url.indexOf(':')+1);
195
+ if (url.startsWith('localStore')) {
196
+ const key = url.substring(url.indexOf(':') + 1);
162
197
 
163
198
  const doc = new DOMParser().parseFromString('<data></data>', 'application/xml');
164
199
  const root = doc.firstElementChild;
165
200
  this.instanceData = doc;
166
201
 
167
- if(!key){
202
+ if (!key) {
168
203
  console.warn('no key specified for localStore');
169
204
  return;
170
205
  }
171
206
 
172
207
  const serialized = localStorage.getItem(key);
173
- if(!serialized){
208
+ if (!serialized) {
174
209
  console.warn(`Data for key ${key} cannot be found`);
175
210
  this._useInlineData();
176
211
  return;
@@ -181,63 +216,28 @@ export class FxInstance extends HTMLElement {
181
216
  doc.firstElementChild.replaceWith(data.firstElementChild);
182
217
  return;
183
218
  }
219
+ const contentType = Fore.getContentType(this, 'get');
184
220
 
185
- await fetch(url, {
186
- method: 'GET',
187
- mode: 'cors',
188
- credentials: 'include',
189
- headers: {
190
- 'Content-Type': contentType,
191
- },
192
- })
193
- .then(response => {
194
- const { status } = response;
195
- if (status >= 400) {
196
- // console.log('response status', status);
197
- alert(`response status: ${status} - failed to load data for '${this.src}' - stopping.`);
198
- throw new Error(`failed to load data - status: ${status}`);
199
- }
200
- const responseContentType = response.headers.get('content-type').toLowerCase();
201
- // console.log('********** responseContentType *********', responseContentType);
202
- if (responseContentType.startsWith('text/html')) {
203
- // const htmlResponse = response.text();
204
- // return new DOMParser().parseFromString(htmlResponse, 'text/html');
205
- // return response.text();
206
- return response.text().then(result =>
207
- // console.log('xml ********', result);
208
- new DOMParser().parseFromString(result, 'text/html'),
209
- );
210
- }
211
- if (
212
- responseContentType.startsWith('text/plain') ||
213
- responseContentType.startsWith('text/markdown')
214
- ) {
215
- // console.log("********** inside res plain *********");
216
- return response.text();
217
- }
218
- if (responseContentType.startsWith('application/json')) {
219
- // console.log("********** inside res json *********");
220
- return response.json();
221
- }
222
- if (responseContentType.startsWith('application/xml')) {
223
- return response.text().then(result =>
224
- // console.log('xml ********', result);
225
- new DOMParser().parseFromString(result, 'application/xml'),
226
- );
227
- }
228
- return 'done';
229
- })
230
- .then(data => {
231
- if (data.nodeType) {
232
- this.instanceData = data;
233
- console.log('instanceData loaded: ', this.id, this.instanceData);
234
- return;
235
- }
236
- this.instanceData = data;
237
- })
238
- .catch(error => {
239
- throw new Error(`failed loading data ${error}`);
221
+ try {
222
+ const response = await fetch(url, {
223
+ method: 'GET',
224
+ mode: 'cors',
225
+ credentials: 'include',
226
+ headers: {
227
+ 'Content-Type': contentType,
228
+ },
240
229
  });
230
+ const { status } = response;
231
+ const data = await handleResponse(response);
232
+ if (data.nodeType) {
233
+ this.instanceData = data;
234
+ console.log('instanceData loaded: ', this.id, this.instanceData);
235
+ return;
236
+ }
237
+ this.instanceData = data;
238
+ } catch (error) {
239
+ throw new Error(`failed loading data ${error}`);
240
+ }
241
241
  }
242
242
 
243
243
  _getContentType() {
package/src/fx-model.js CHANGED
@@ -95,7 +95,7 @@ export class FxModel extends HTMLElement {
95
95
  * @event model-construct-done is fired once all instances have be loaded or after generating instance
96
96
  *
97
97
  */
98
- modelConstruct() {
98
+ async modelConstruct() {
99
99
  // console.log('### <<<<< dispatching model-construct >>>>>');
100
100
  // this.dispatchEvent(new CustomEvent('model-construct', { detail: this }));
101
101
  Fore.dispatch(this, 'model-construct', {model: this});
@@ -109,17 +109,20 @@ export class FxModel extends HTMLElement {
109
109
  promises.push(instance.init());
110
110
  });
111
111
 
112
- Promise.all(promises).then(() => {
113
- this.instances = Array.from(instances);
114
- // console.log('_modelConstruct this.instances ', this.instances);
115
- this.updateModel();
116
- this.inited = true;
117
- Fore.dispatch(this, 'model-construct-done', {model: this});
118
- });
112
+ // Wait until all the instances are built
113
+ await Promise.all(promises);
114
+
115
+ this.instances = Array.from(instances);
116
+ // console.log('_modelConstruct this.instances ', this.instances);
117
+ // Await until the model-construct-done event is handled off
118
+
119
+ await Fore.dispatch(this, 'model-construct-done', {model: this});
120
+ this.inited = true;
121
+ this.updateModel();
119
122
  console.groupEnd();
120
123
  } else {
121
124
  // ### if there's no instance one will created
122
- this.dispatchEvent(
125
+ await this.dispatchEvent(
123
126
  new CustomEvent('model-construct-done', {
124
127
  composed: false,
125
128
  bubbles: true,
@@ -387,14 +390,6 @@ export class FxModel extends HTMLElement {
387
390
  modelItem.constraint = compute;
388
391
  this.formElement.addToRefresh(modelItem); // let fore know that modelItem needs refresh
389
392
  if (!compute) valid = false;
390
- // ### alerts are added only once during model-construct. Otherwise they would add up in each run of revalidate()
391
- if (!this.modelConstructed) {
392
- // todo: get alert from attribute or child element
393
- const alert = bind.getAlert();
394
- if (alert) {
395
- modelItem.addAlert(alert);
396
- }
397
- }
398
393
  }
399
394
  }
400
395
  if (typeof bind.hasAttribute === 'function' && bind.hasAttribute('required')) {