@processmaker/screen-builder 2.21.1 → 2.24.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.
package/package-lock.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@processmaker/screen-builder",
3
- "version": "2.21.1",
3
+ "version": "2.24.0",
4
4
  "lockfileVersion": 1,
5
5
  "requires": true,
6
6
  "dependencies": {
@@ -1738,9 +1738,9 @@
1738
1738
  }
1739
1739
  },
1740
1740
  "@processmaker/vue-form-elements": {
1741
- "version": "0.28.2",
1742
- "resolved": "https://registry.npmjs.org/@processmaker/vue-form-elements/-/vue-form-elements-0.28.2.tgz",
1743
- "integrity": "sha512-oHFBh/BTfsUmE6RXpTVbi+UfzIKdRBJWwXs2xz/N3I2e8EyQZBotOoK6uq6TsavttLZ2wm4LWKJ9kHygI3FnGw==",
1741
+ "version": "0.28.6",
1742
+ "resolved": "https://registry.npmjs.org/@processmaker/vue-form-elements/-/vue-form-elements-0.28.6.tgz",
1743
+ "integrity": "sha512-uxHsOkCNLJEF4mJu7dK4+qn2SL/mWDswdoV1kQjNjQkwBk10uGXDdAbtliHRbld3HDMAPUQAu69c+1fS8pDqjA==",
1744
1744
  "dev": true,
1745
1745
  "requires": {
1746
1746
  "@tinymce/tinymce-vue": "2.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@processmaker/screen-builder",
3
- "version": "2.21.1",
3
+ "version": "2.24.0",
4
4
  "scripts": {
5
5
  "serve": "vue-cli-service serve",
6
6
  "build": "vue-cli-service build",
@@ -44,7 +44,7 @@
44
44
  "@cypress/code-coverage": "^3.8.1",
45
45
  "@fortawesome/fontawesome-free": "^5.6.1",
46
46
  "@panter/vue-i18next": "^0.15.2",
47
- "@processmaker/vue-form-elements": "0.28.2",
47
+ "@processmaker/vue-form-elements": "0.28.6",
48
48
  "@processmaker/vue-multiselect": "^2.2.0",
49
49
  "@vue/cli-plugin-babel": "^3.6.0",
50
50
  "@vue/cli-plugin-e2e-cypress": "^4.0.3",
@@ -85,7 +85,7 @@
85
85
  },
86
86
  "peerDependencies": {
87
87
  "@panter/vue-i18next": "^0.15.0",
88
- "@processmaker/vue-form-elements": "0.28.1",
88
+ "@processmaker/vue-form-elements": "0.28.6",
89
89
  "i18next": "^15.0.8",
90
90
  "vue": "^2.6.12",
91
91
  "vuex": "^3.1.1"
@@ -1,6 +1,6 @@
1
1
  import { validators } from './mixins/ValidationRules';
2
2
  import DataProvider from './DataProvider';
3
- import { get, set } from 'lodash';
3
+ import { get, set, merge } from 'lodash';
4
4
  import { Parser } from 'expr-eval';
5
5
 
6
6
  let globalObject = typeof window === 'undefined'
@@ -34,7 +34,7 @@ class Validations {
34
34
  isVisible() {
35
35
  // Disable validations if field is hidden
36
36
  let visible = true;
37
- if (this.element.config.conditionalHide) {
37
+ if (!this.data.noData && this.element.config.conditionalHide) {
38
38
  try {
39
39
  visible = !!Parser.evaluate(this.element.config.conditionalHide, this.data);
40
40
  } catch (error) {
@@ -51,7 +51,7 @@ class Validations {
51
51
  class ArrayOfFieldsValidations extends Validations {
52
52
  async addValidations(validations) {
53
53
  for (const item of this.element) {
54
- await ValidationsFactory(item, { screen: this.screen, data: this.data }).addValidations(validations);
54
+ await ValidationsFactory(item, { screen: this.screen, data: this.data, parentVisibilityRule: this.parentVisibilityRule }).addValidations(validations);
55
55
  }
56
56
  }
57
57
  }
@@ -81,8 +81,9 @@ class FormNestedScreenValidations extends Validations {
81
81
  return;
82
82
  }
83
83
  const definition = await this.loadScreen(this.element.config.screen);
84
+ let parentVisibilityRule = this.parentVisibilityRule ? this.parentVisibilityRule : this.element.config.conditionalHide;
84
85
  if (definition && definition[0] && definition[0].items) {
85
- await ValidationsFactory(definition[0].items, { screen: this.screen, data: this.data }).addValidations(validations);
86
+ await ValidationsFactory(definition[0].items, { screen: this.screen, data: this.data, parentVisibilityRule }).addValidations(validations);
86
87
  }
87
88
  }
88
89
 
@@ -112,8 +113,53 @@ class FormLoopValidations extends Validations {
112
113
  set(validations, this.element.config.name, {});
113
114
  const loopField = get(validations, this.element.config.name);
114
115
  loopField['$each'] = {};
115
- const firstRow = (get(this.data, this.element.config.name) || [{}])[0];
116
- await ValidationsFactory(this.element.items, { screen: this.screen, data: {_parent: this.data, ...firstRow } }).addValidations(loopField['$each']);
116
+ this.checkForSiblings(validations);
117
+ await ValidationsFactory(this.element.items, { screen: this.screen, data: {_parent: this.data, noData:true }, parentVisibilityRule: this.element.config.conditionalHide }).addValidations(loopField['$each']);
118
+ }
119
+ checkForSiblings(validations) {
120
+ const siblings = [];
121
+ const siblingValidations = [];
122
+ // Find loops that reference the same variable
123
+ this.screen.config.forEach(page => {
124
+ page.items.filter(item => {
125
+ if (item.component === 'FormLoop' && item.config.name === this.element.config.name) {
126
+ siblings.push(item);
127
+ }
128
+ });
129
+
130
+ // Get siblings validations
131
+ if (siblings) {
132
+ siblings.forEach(sibling => {
133
+ sibling.items.filter(item => {
134
+ if (!item.config.validation) {
135
+ return;
136
+ }
137
+
138
+ item.config.validation.forEach(validation => {
139
+ const rule = this.camelCase(validation.value.split(':')[0]);
140
+ const validationFn = validators[rule];
141
+ const obj = {};
142
+ let ruleObj = {};
143
+ ruleObj[rule] = validationFn;
144
+ obj[item.config.name] = ruleObj;
145
+ merge(siblingValidations, obj);
146
+ });
147
+ });
148
+ });
149
+ }
150
+ });
151
+
152
+ if (Object.keys(siblingValidations).length != 0) {
153
+ // Update the loop validations with its siblings.
154
+ const loopValidations = get(validations, this.element.config.name);
155
+ if (loopValidations.hasOwnProperty('$each')) {
156
+ merge(loopValidations['$each'], siblingValidations);
157
+ }
158
+ set(validations[this.element.config.name]['$each'], loopValidations);
159
+ }
160
+ }
161
+ camelCase(name) {
162
+ return name.replace(/_\w/g, m => m.substr(1, 1).toUpperCase());
117
163
  }
118
164
  }
119
165
 
@@ -126,7 +172,7 @@ class FormMultiColumnValidations extends Validations {
126
172
  if (!this.isVisible()) {
127
173
  return;
128
174
  }
129
- await ValidationsFactory(this.element.items, { screen: this.screen, data: this.data }).addValidations(validations);
175
+ await ValidationsFactory(this.element.items, { screen: this.screen, data: this.data, parentVisibilityRule: this.element.config.conditionalHide }).addValidations(validations);
130
176
  }
131
177
  }
132
178
 
@@ -167,19 +213,8 @@ class FormElementValidations extends Validations {
167
213
  }
168
214
  const fieldName = this.element.config.name;
169
215
  const validationConfig = this.element.config.validation;
170
-
171
- // Disable validations if field is hidden
172
- if (this.element.config.conditionalHide) {
173
- let visible = true;
174
- try {
175
- visible = !!Parser.evaluate(this.element.config.conditionalHide, this.data);
176
- } catch (error) {
177
- visible = false;
178
- }
179
- if (!visible) {
180
- return;
181
- }
182
- }
216
+ const conditionalHide = this.element.config.conditionalHide;
217
+ const parentVisibilityRule = this.parentVisibilityRule;
183
218
 
184
219
  set(validations, fieldName, get(validations, fieldName, {}));
185
220
  const fieldValidation = get(validations, fieldName);
@@ -203,7 +238,40 @@ class FormElementValidations extends Validations {
203
238
  params.push(fieldName);
204
239
  validationFn = validationFn(...params);
205
240
  }
206
- fieldValidation[rule] = validationFn;
241
+ fieldValidation[rule] = function(...props) {
242
+ const data = props[1];
243
+ let dataWithParent = this.addReferenceToParents(data);
244
+ const nestedDataWithParent = this.addReferenceToParents(this.findParent(data));
245
+ if (nestedDataWithParent) {
246
+ dataWithParent = Object.assign(nestedDataWithParent, dataWithParent);
247
+ }
248
+ // Check Parent Visibility
249
+ if (parentVisibilityRule) {
250
+ let isParentVisible = true;
251
+ try {
252
+ isParentVisible = !!Parser.evaluate(parentVisibilityRule, dataWithParent);
253
+ } catch (error) {
254
+ isParentVisible = false;
255
+ }
256
+
257
+ if (!isParentVisible ) {
258
+ return true;
259
+ }
260
+ }
261
+ // Check Field Visibility
262
+ let visible = true;
263
+ if (conditionalHide) {
264
+ try {
265
+ visible = !!Parser.evaluate(conditionalHide, dataWithParent);
266
+ } catch (error) {
267
+ visible = false;
268
+ }
269
+ }
270
+ if (!visible) {
271
+ return true;
272
+ }
273
+ return validationFn.apply(this,props);
274
+ };
207
275
  });
208
276
  } else if (typeof validationConfig === 'string' && validationConfig) {
209
277
  let validationFn = validators[validationConfig];
@@ -212,7 +280,40 @@ class FormElementValidations extends Validations {
212
280
  console.error(`Undefined validation rule "${validationConfig}"`);
213
281
  return;
214
282
  }
215
- fieldValidation[validationConfig] = validationFn;
283
+ fieldValidation[validationConfig] = function(...props) {
284
+ const data = props[1];
285
+ let dataWithParent = this.addReferenceToParents(data);
286
+ const nestedDataWithParent = this.addReferenceToParents(this.findParent(data));
287
+ if (nestedDataWithParent) {
288
+ dataWithParent = Object.assign(nestedDataWithParent, dataWithParent);
289
+ }
290
+ // Check Parent Visibility
291
+ if (parentVisibilityRule) {
292
+ let isParentVisible = true;
293
+ try {
294
+ isParentVisible = !!Parser.evaluate(parentVisibilityRule, dataWithParent);
295
+ } catch (error) {
296
+ isParentVisible = false;
297
+ }
298
+
299
+ if (!isParentVisible) {
300
+ return true;
301
+ }
302
+ }
303
+ // Check Field Visibility
304
+ let visible = true;
305
+ if (conditionalHide) {
306
+ try {
307
+ visible = !!Parser.evaluate(conditionalHide, dataWithParent);
308
+ } catch (error) {
309
+ visible = false;
310
+ }
311
+ }
312
+ if (!visible) {
313
+ return true;
314
+ }
315
+ return validationFn.apply(this,props);
316
+ };
216
317
  }
217
318
  if (this.element.items) {
218
319
  ValidationsFactory(this.element.items, { screen: this.screen, data: this.data }).addValidations(validations);
@@ -20,10 +20,13 @@
20
20
  :data-manager="dataManager"
21
21
  :fields="tableFields"
22
22
  :items="tableData.data"
23
+ :sort-compare-options="{ numeric: false }"
23
24
  sort-icon-left
24
25
  :css="css"
25
26
  :empty-text="$t('No Data Available')"
26
27
  :current-page="currentPage"
28
+ @sort-changed="sortChanged"
29
+ @input="onInput"
27
30
  data-cy="table"
28
31
  >
29
32
  <template #cell()="{index,field,item}">
@@ -74,6 +77,7 @@
74
77
  :title="$t('Add')"
75
78
  header-close-content="&times;"
76
79
  data-cy="modal-add"
80
+ @shown="emitShownEvent"
77
81
  >
78
82
  <vue-form-renderer
79
83
  :page="0"
@@ -99,6 +103,7 @@
99
103
  :title="$t('Edit Record')"
100
104
  header-close-content="&times;"
101
105
  data-cy="modal-edit"
106
+ @shown="emitShownEvent"
102
107
  >
103
108
  <vue-form-renderer
104
109
  :page="0"
@@ -161,7 +166,7 @@ const jsonOptionsActionsColumn = {
161
166
 
162
167
  export default {
163
168
  mixins: [mustacheEvaluation],
164
- props: ['name', 'label', 'fields', 'value', 'editable', '_config', 'form', 'validationData', 'formConfig', 'formComputed', 'formWatchers'],
169
+ props: ['name', 'label', 'fields', 'value', 'editable', '_config', 'form', 'validationData', 'formConfig', 'formComputed', 'formWatchers', '_perPage'],
165
170
  data() {
166
171
  return {
167
172
  editFormVersion: 0,
@@ -192,6 +197,11 @@ export default {
192
197
  initFormValues: {},
193
198
  };
194
199
  },
200
+ mounted() {
201
+ if (this._perPage) {
202
+ this.perPage = this._perPage;
203
+ }
204
+ },
195
205
  computed: {
196
206
  popupConfig() {
197
207
  const config = [];
@@ -240,6 +250,7 @@ export default {
240
250
  from,
241
251
  to: value.length,
242
252
  data: value,
253
+ lastSortConfig: false,
243
254
  };
244
255
  return data;
245
256
  },
@@ -258,7 +269,35 @@ export default {
258
269
  return this.form && this.form === this.$parent.currentPage;
259
270
  },
260
271
  },
272
+ watch: {
273
+ 'tableData.total': {
274
+ deep: true,
275
+ handler(total) {
276
+ let totalPages = Math.ceil(total / this.perPage);
277
+ this.currentPage = (this.currentPage > totalPages ? totalPages : this.currentPage);
278
+ this.currentPage = (this.currentPage == 0 ? 1 : this.currentPage);
279
+ },
280
+ },
281
+ },
261
282
  methods: {
283
+ sortChanged(payload) {
284
+ this.lastSortConfig = payload;
285
+ this.tableData.data = this.sort(this.tableData.data, payload);
286
+ },
287
+ onInput() {
288
+ if (this.lastSortConfig) {
289
+ this.tableData.data = this.sort(this.tableData.data, this.lastSortConfig);
290
+ }
291
+ },
292
+ sort(data, options) {
293
+ if (options.sortDesc) {
294
+ return data.sort((b,a) => a[options.sortBy].localeCompare(b[options.sortBy], 0, {numeric: false}));
295
+ }
296
+ return data.sort((a,b) => a[options.sortBy].localeCompare(b[options.sortBy], 0, {numeric: false}));
297
+ },
298
+ emitShownEvent() {
299
+ window.ProcessMaker.EventBus.$emit('modal-shown');
300
+ },
262
301
  formatIfDate(string) {
263
302
  return dateUtils.formatIfDate(string);
264
303
  },
@@ -337,9 +376,9 @@ export default {
337
376
  }
338
377
  },
339
378
  showEditForm(index) {
340
- let pageIndex = ((this.paginatorPage-1) * this.perPage) + index;
379
+ let pageIndex = ((this.currentPage-1) * this.perPage) + index;
341
380
  // Reset edit to be a copy of our data model item
342
- this.editItem = JSON.parse(JSON.stringify(this.value[pageIndex]));
381
+ this.editItem = JSON.parse(JSON.stringify(this.tableData.data[pageIndex]));
343
382
  this.editIndex = pageIndex;
344
383
  // rebuild the edit screen to avoid
345
384
  this.editFormVersion++;
@@ -349,13 +388,13 @@ export default {
349
388
  });
350
389
  },
351
390
  edit(event) {
352
- if (this.$refs.editRenderer.$refs.renderer.$refs.component.$v.$invalid) {
391
+ if (this.$refs.editRenderer.$refs.renderer.$refs.component.$v.vdata.$invalid) {
353
392
  event.preventDefault();
354
393
  return;
355
394
  }
356
395
 
357
396
  // Edit the item in our model and emit change
358
- let data = this.value ? JSON.parse(JSON.stringify(this.value)) : [];
397
+ let data = this.tableData.data ? JSON.parse(JSON.stringify(this.tableData.data)) : [];
359
398
  data[this.editIndex] = JSON.parse(JSON.stringify(this.editItem));
360
399
 
361
400
  // Remove the parent object
@@ -382,7 +421,7 @@ export default {
382
421
  handleOk(bvModalEvt) {
383
422
  bvModalEvt.preventDefault();
384
423
 
385
- if (this.$refs.addRenderer.$refs.renderer.$refs.component.$v.$invalid) {
424
+ if (this.$refs.addRenderer.$refs.renderer.$refs.component.$v.vdata.$invalid) {
386
425
  return;
387
426
  }
388
427
 
@@ -405,7 +444,7 @@ export default {
405
444
  });
406
445
  },
407
446
  showDeleteConfirmation(index) {
408
- let pageIndex = ((this.paginatorPage-1) * this.perPage) + index;
447
+ let pageIndex = ((this.currentPage-1) * this.perPage) + index;
409
448
  this.deleteIndex = pageIndex;
410
449
  this.$refs.deleteModal.show();
411
450
  },
@@ -442,7 +481,7 @@ export default {
442
481
  remove() {
443
482
  // Add the item to our model and emit change
444
483
  // @todo Also check that value is an array type, if not, reset it to an array
445
- let data = this.value ? JSON.parse(JSON.stringify(this.value)) : [];
484
+ let data = this.tableData.data ? JSON.parse(JSON.stringify(this.tableData.data)) : [];
446
485
  let recordData = data[this.deleteIndex];
447
486
  // Remove item from data array
448
487
  data.splice(this.deleteIndex, 1);
@@ -459,3 +498,4 @@ export default {
459
498
  max-width: 300px;
460
499
  }
461
500
  </style>
501
+
@@ -242,6 +242,11 @@ export default {
242
242
  .then((response) => {
243
243
  this.task = response.data;
244
244
  this.checkTaskStatus();
245
+ if (window.PM4ConfigOverrides.getScreenEndpoint && window.PM4ConfigOverrides.getScreenEndpoint.includes('tasks/')) {
246
+ const screenPath = window.PM4ConfigOverrides.getScreenEndpoint.split('/');
247
+ screenPath[1] = this.task.id;
248
+ window.PM4ConfigOverrides.getScreenEndpoint = screenPath.join('/');
249
+ }
245
250
  })
246
251
  .catch(() => {
247
252
  this.hasErrors = true;
@@ -279,19 +284,19 @@ export default {
279
284
  }
280
285
  this.prepareTask();
281
286
  },
282
- closeTask() {
287
+ closeTask(parentRequestId = null) {
283
288
  if (this.hasErrors) {
284
289
  this.$emit('error', this.requestId);
285
290
  return;
286
291
  }
287
292
 
288
293
  if (this.task.process_request.status === 'COMPLETED') {
289
- this.processCompleted();
294
+ this.loadNextAssignedTask(parentRequestId);
290
295
 
291
296
  } else if (this.task.allow_interstitial) {
292
297
  this.task.interstitial_screen['_interstitial'] = true;
293
298
  this.screen = this.task.interstitial_screen;
294
- this.loadNextAssignedTask();
299
+ this.loadNextAssignedTask(parentRequestId);
295
300
 
296
301
  } else {
297
302
  this.$emit('closed', this.task.id);
@@ -313,11 +318,16 @@ export default {
313
318
  }
314
319
  this.unsubscribeSocketListeners();
315
320
  this.redirecting = task.process_request_id;
316
- this.$emit('redirect', task);
321
+ this.$emit('redirect', task.id, true);
317
322
  return;
323
+ } else if (this.task && requestId == this.task.process_request_id && this.parentRequest && this.task.process_request.status === 'COMPLETED') {
324
+ // Only emit completed after getting the subprocess tasks and there are no tasks and process is completed
325
+ this.$emit('completed', this.parentRequest);
318
326
  }
319
327
  this.taskId = task.id;
320
328
  this.nodeId = task.element_id;
329
+ } else {
330
+ this.$emit('completed', (this.parentRequest ? this.parentRequest : requestId));
321
331
  }
322
332
  });
323
333
  },
@@ -361,9 +371,8 @@ export default {
361
371
  // This may no longer be needed
362
372
  },
363
373
  processCompleted() {
364
- if (this.parentRequest && this.task.allow_interstitial) {
365
- // There could be another task in the parent, so don't emit completed
366
- return;
374
+ if (this.parentRequest) {
375
+ this.$emit('completed', this.parentRequest);
367
376
  }
368
377
  this.$emit('completed', this.requestId);
369
378
  },
@@ -412,8 +421,13 @@ export default {
412
421
  `ProcessMaker.Models.ProcessRequest.${this.parentRequest}`,
413
422
  '.ProcessUpdated',
414
423
  (data) => {
415
- if (['ACTIVITY_COMPLETED', 'ACTIVITY_ACTIVATED'].includes(data.event)) {
416
- this.loadNextAssignedTask(this.parentRequest);
424
+ if (['ACTIVITY_ACTIVATED'].includes(data.event)) {
425
+ this.closeTask(this.parentRequest);
426
+ }
427
+ if (['ACTIVITY_COMPLETED'].includes(data.event)) {
428
+ if (this.task.process_request.status === 'COMPLETED') {
429
+ this.processCompleted();
430
+ }
417
431
  }
418
432
  if (data.event === 'ACTIVITY_EXCEPTION') {
419
433
  this.$emit('error', this.requestId);
@@ -96,7 +96,8 @@ export const keyNameProperty = {
96
96
  config: {
97
97
  label: 'Variable Name',
98
98
  name: 'Variable Name',
99
- validation: 'regex:/^(?:[A-Za-z])(?:[0-9A-Z_.a-z])*[^.]$/|required|not_in:' + javascriptReservedKeywords,
99
+ // Update tests/e2e/specs/Builder.spec.js when changing this
100
+ validation: 'regex:/^([a-zA-Z]([a-zA-Z0-9_]?)+\\.?)+(?<!\\.)$/|required|not_in:' + javascriptReservedKeywords,
100
101
  helper: 'A variable name is a symbolic name to reference information.',
101
102
  },
102
103
  };
package/src/main.js CHANGED
@@ -152,7 +152,7 @@ window.ProcessMaker = {
152
152
  {value: 2, content: 'John'},
153
153
  {value: 3, content: 'Mary'},
154
154
  {value: 4, content: 'Patricia'},
155
- ],
155
+ ],
156
156
  }});
157
157
  break;
158
158
  default:
@@ -201,6 +201,16 @@ window.Echo = {
201
201
  }, 1000);
202
202
  });
203
203
  },
204
+ eventMocks(event, response) {
205
+ this.listeners.forEach((listener) => {
206
+ setTimeout(() => {
207
+ listener.callback({
208
+ type: event,
209
+ response,
210
+ });
211
+ }, 1000);
212
+ });
213
+ },
204
214
  private() {
205
215
  return {
206
216
  notification(callback) {
@@ -93,7 +93,8 @@ export default {
93
93
  },
94
94
  tryFormField(variableName, callback, defaultValue = null) {
95
95
  try {
96
- return callback();
96
+ let result = callback();
97
+ return (result === undefined) ? null : result;
97
98
  } catch (e) {
98
99
  set(this.$v, `${variableName}.$invalid`, true);
99
100
  set(this.$v, `${variableName}.invalid_default_value`, false);
@@ -102,7 +103,15 @@ export default {
102
103
  },
103
104
  mustache(text) {
104
105
  try {
105
- const data = Object.assign({_parent: this._parent}, this.vdata);
106
+ const data = new Proxy(this, {
107
+ get(target, name) {
108
+ if (name === '_parent') {
109
+ return target._parent;
110
+ } else {
111
+ return target.vdata[name];
112
+ }
113
+ },
114
+ });
106
115
  return text && Mustache.render(text, data);
107
116
  } catch (e) {
108
117
  return 'MUSTACHE: ' + e.message;
@@ -146,21 +155,17 @@ export default {
146
155
  },
147
156
  setValue(name, value, object = this, defaults = object) {
148
157
  if (object && value !== undefined) {
149
- const splittedName = name.split('.');
150
- splittedName.forEach((attr, index) => {
158
+ const parsedName = name.split('.');
151
159
 
152
- let isLastElement, setValue;
153
- const originalValue = get(object, attr);
160
+ for (const attr of parsedName) {
161
+ let setValue;
162
+ let index = parsedName.indexOf(attr);
163
+ let isLastElement = index === parsedName.length - 1;
154
164
 
155
- if (index === splittedName.length - 1) {
156
- isLastElement = true;
157
- } else {
158
- isLastElement = false;
159
- }
165
+ const originalValue = get(object, attr);
160
166
 
161
167
  if (isLastElement) {
162
168
  setValue = value;
163
-
164
169
  } else {
165
170
  setValue = originalValue;
166
171
 
@@ -168,7 +173,7 @@ export default {
168
173
  // Check defaults
169
174
  setValue = get(defaults, attr);
170
175
  }
171
-
176
+
172
177
  if (!setValue) {
173
178
  // Still no value? Set empty object
174
179
  setValue = {};
@@ -184,9 +189,10 @@ export default {
184
189
  attr,
185
190
  setValue
186
191
  );
192
+
187
193
  object = get(object, attr);
188
194
  defaults = get(defaults, attr);
189
- });
195
+ }
190
196
  }
191
197
  },
192
198
  validationMessage(validation) {
@@ -23,6 +23,7 @@ import {
23
23
  and,
24
24
  maxItems,
25
25
  minItems,
26
+ type,
26
27
  } from 'vuelidate/lib/validators';
27
28
 
28
29
  export const ValidationMsg = {
@@ -59,6 +60,7 @@ export const ValidationMsg = {
59
60
  regex: 'Invalid value',
60
61
  maxItems: 'Should NOT have more than {max} items',
61
62
  minItems: 'Must have at least {min}',
63
+ type: 'Invalid type',
62
64
  };
63
65
 
64
66
  export const custom_date = (date) => {
@@ -231,4 +233,5 @@ export const validators = {
231
233
  afterOrEqual: after_or_equal,
232
234
  maxItems,
233
235
  minItems,
236
+ type,
234
237
  };
@@ -1,20 +1,18 @@
1
- import _ from 'lodash';
2
1
  import { Parser } from 'expr-eval';
3
2
 
4
3
  export default {
5
4
  methods: {
6
5
  evaluateExpression(expression, type) {
6
+ const self = this;
7
7
  let value = null;
8
8
 
9
- const merged = {};
10
- _.merge(merged, this.vdata, this._data);
11
-
12
9
  try {
13
- //monitor if variable belongs to data (defined variables) or vdata (external variables)
14
- //in this way the event is not executed again when the variable is update
15
- const data = new Proxy(merged, {
10
+ // Monitor if variable belongs to data (defined variables) or
11
+ // vdata (external variables)in this way the event is not
12
+ // executed again when the variable is update
13
+ const data = new Proxy(Object.assign({}, self, self.vdata), {
16
14
  get(data, name) {
17
- return data[name];
15
+ return undefined === data[name] ? self.vdata[name] : data[name];
18
16
  },
19
17
  set() {
20
18
  throw 'You are not allowed to set properties from inside an expression';
@@ -3,14 +3,28 @@ import computedFields from '../computedFields';
3
3
  export default {
4
4
  methods: {
5
5
  computedFields(screen, definition) {
6
+ // Add computed fields
6
7
  screen.mixins.push(computedFields);
7
- definition.computed.forEach(computed => {
8
+
9
+ for (const computed of definition.computed) {
8
10
  screen.computed[computed.property] = {
9
- get: new Function(`return this.evaluateExpression(${JSON.stringify(computed.formula)}, ${JSON.stringify(computed.type)});`),
10
- set() {},
11
+ get: (() => {
12
+ const formula = JSON.stringify(computed.formula);
13
+ const type = JSON.stringify(computed.type);
14
+
15
+ return new Function(`return this.evaluateExpression(${formula}, ${type});`);
16
+ })(),
17
+ set() {
18
+ // Do nothing (as it's not allowed)
19
+ },
11
20
  };
12
- this.addWatch(screen, computed.property, `this.setValue(${JSON.stringify(computed.property)}, value, this.vdata);`);
13
- });
21
+
22
+ this.addWatch(
23
+ screen,
24
+ computed.property,
25
+ `this.setValue(${JSON.stringify(computed.property)}, value, this.vdata);`
26
+ );
27
+ }
14
28
  },
15
29
  },
16
30
  mounted() {