From cf9053ab46d8ceb9b76014db1ac607621fbcba5c Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 17 Oct 2016 14:44:23 +0100 Subject: [PATCH] Dynamic-table widget placeholder - project structure for dynamic-table widget - support for multiple root element types (container, dynamic table, etc) - code improvements and updates --- .../components/activiti-form.component.html | 14 ++++- .../activiti-form.component.spec.ts | 4 +- .../widgets/core/container.model.ts | 14 +++++ .../widgets/core/dynamic-table.model.ts | 34 +++++++++++ .../widgets/core/form-widget.model.spec.ts | 10 ++- .../widgets/core/form-widget.model.ts | 2 +- .../widgets/core/form.model.spec.ts | 31 +++++++--- .../src/components/widgets/core/form.model.ts | 61 +++++++++++-------- .../src/components/widgets/core/index.ts | 1 + .../src/components/widgets/core/tab.model.ts | 3 +- .../dynamic-table/dynamic-table.widget.css | 19 ++++++ .../dynamic-table/dynamic-table.widget.html | 6 ++ .../dynamic-table/dynamic-table.widget.ts | 30 +++++++++ .../src/components/widgets/index.ts | 5 +- .../components/widgets/tabs/tabs.widget.html | 14 +++-- .../src/services/widget-visibility.service.ts | 9 +-- 16 files changed, 203 insertions(+), 54 deletions(-) create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table.model.ts create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.css create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.html create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.ts diff --git a/ng2-components/ng2-activiti-form/src/components/activiti-form.component.html b/ng2-components/ng2-activiti-form/src/components/activiti-form.component.html index f42f0b9900..f3fcda7a3e 100644 --- a/ng2-components/ng2-activiti-form/src/components/activiti-form.component.html +++ b/ng2-components/ng2-activiti-form/src/components/activiti-form.component.html @@ -14,7 +14,19 @@
- +
+
+
+ +
+
+ +
+
+ UNKNOWN WIDGET TYPE: {{field.type}} +
+
+
diff --git a/ng2-components/ng2-activiti-form/src/components/activiti-form.component.spec.ts b/ng2-components/ng2-activiti-form/src/components/activiti-form.component.spec.ts index 04d20b3989..14ee3e96aa 100644 --- a/ng2-components/ng2-activiti-form/src/components/activiti-form.component.spec.ts +++ b/ng2-components/ng2-activiti-form/src/components/activiti-form.component.spec.ts @@ -18,7 +18,7 @@ import { Observable } from 'rxjs/Rx'; import { SimpleChange } from '@angular/core'; import { ActivitiForm } from './activiti-form.component'; -import { FormModel, FormOutcomeModel, FormFieldModel, FormOutcomeEvent } from './widgets/index'; +import { FormModel, FormOutcomeModel, FormFieldModel, FormOutcomeEvent, FormFieldTypes } from './widgets/index'; import { FormService } from './../services/form.service'; import { WidgetVisibilityService } from './../services/widget-visibility.service'; import { NodeService } from './../services/node.service'; @@ -554,7 +554,7 @@ describe('ActivitiForm', () => { let form = formComponent.parseForm({ id: '', fields: [ - { id: 'field1' } + { id: 'field1', type: FormFieldTypes.CONTAINER } ] }); diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/container.model.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/container.model.ts index e39acb78a0..c39d24d5cb 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/container.model.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/container.model.ts @@ -87,4 +87,18 @@ export class ContainerModel extends FormWidgetModel { this.isExpanded = !this.isCollapsedByDefault(); } } + + getFormFields(): FormFieldModel[] { + let result: FormFieldModel[] = []; + + for (let j = 0; j < this.columns.length; j++) { + let column = this.columns[j]; + for (let k = 0; k < column.fields.length; k++) { + let field = column.fields[k]; + result.push(field); + } + } + + return result; + } } diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table.model.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table.model.ts new file mode 100644 index 0000000000..05115306a6 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table.model.ts @@ -0,0 +1,34 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FormWidgetModel } from './form-widget.model'; +import { FormModel } from './form.model'; +import { FormFieldModel } from './form-field.model'; + +export class DynamicTableModel extends FormWidgetModel { + + field: FormFieldModel; + + constructor(form: FormModel, json?: any) { + super(form, json); + + if (json) { + this.field = new FormFieldModel(form, json); + } + } + +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-widget.model.spec.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-widget.model.spec.ts index 29b0dcb6ca..18198a3cf6 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-widget.model.spec.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-widget.model.spec.ts @@ -20,15 +20,21 @@ import { FormWidgetModel } from './form-widget.model'; describe('FormWidgetModel', () => { + class FormWidgetModelMock extends FormWidgetModel { + constructor(form: FormModel, json: any) { + super(form, json); + } + } + it('should store the form reference', () => { let form = new FormModel(); - let model = new FormWidgetModel(form, null); + let model = new FormWidgetModelMock(form, null); expect(model.form).toBe(form); }); it('should store original json', () => { let json = {}; - let model = new FormWidgetModel(null, json); + let model = new FormWidgetModelMock(null, json); expect(model.json).toBe(json); }); diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-widget.model.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-widget.model.ts index f01ad71d5a..7e5c173204 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-widget.model.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-widget.model.ts @@ -17,7 +17,7 @@ import { FormModel } from './form.model'; -export class FormWidgetModel { +export abstract class FormWidgetModel { readonly fieldType: string; readonly id: string; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.spec.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.spec.ts index 21e1993240..7fabcd0722 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.spec.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.spec.ts @@ -20,6 +20,7 @@ import { TabModel } from './tab.model'; import { ContainerModel } from './container.model'; import { FormOutcomeModel } from './form-outcome.model'; import { FormValues } from './form-values'; +import { FormFieldTypes } from './form-field-types'; describe('FormModel', () => { @@ -118,8 +119,14 @@ describe('FormModel', () => { it('should parse fields', () => { let json = { fields: [ - { id: 'field1' }, - { id: 'field2' } + { + id: 'field1', + type: FormFieldTypes.CONTAINER + }, + { + id: 'field2', + type: FormFieldTypes.CONTAINER + } ] }; @@ -134,8 +141,14 @@ describe('FormModel', () => { fields: null, formDefinition: { fields: [ - { id: 'field1' }, - { id: 'field2' } + { + id: 'field1', + type: FormFieldTypes.CONTAINER + }, + { + id: 'field2', + type: FormFieldTypes.CONTAINER + } ] } }; @@ -163,10 +176,10 @@ describe('FormModel', () => { { id: 'tab2' } ], fields: [ - { id: 'field1', tab: 'tab1' }, - { id: 'field2', tab: 'tab2' }, - { id: 'field3', tab: 'tab1' }, - { id: 'field4', tab: 'missing-tab' } + { id: 'field1', tab: 'tab1', type: FormFieldTypes.CONTAINER }, + { id: 'field2', tab: 'tab2', type: FormFieldTypes.CONTAINER }, + { id: 'field3', tab: 'tab1', type: FormFieldTypes.DYNAMIC_TABLE }, + { id: 'field4', tab: 'missing-tab', type: FormFieldTypes.DYNAMIC_TABLE } ] }; @@ -226,7 +239,7 @@ describe('FormModel', () => { let form = new FormModel(json, data); expect(form.fields.length).toBe(1); - let container = form.fields[0]; + let container = form.fields[0]; expect(container.columns.length).toBe(2); let column1 = container.columns[0]; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.ts index 878da23656..7255ade4df 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.ts @@ -15,12 +15,14 @@ * limitations under the License. */ -import { FormWidgetModelCache } from './form-widget.model'; +import { FormWidgetModel, FormWidgetModelCache } from './form-widget.model'; import { FormValues } from './form-values'; import { ContainerModel } from './container.model'; import { TabModel } from './tab.model'; import { FormOutcomeModel } from './form-outcome.model'; import { FormFieldModel } from './form-field.model'; +import { FormFieldTypes } from './form-field-types'; +import { DynamicTableModel } from './dynamic-table.model'; export class FormModel { @@ -41,7 +43,7 @@ export class FormModel { readOnly: boolean = false; tabs: TabModel[] = []; - fields: ContainerModel[] = []; + fields: FormWidgetModel[] = []; outcomes: FormOutcomeModel[] = []; values: FormValues = {}; @@ -62,6 +64,7 @@ export class FormModel { constructor(json?: any, data?: FormValues, readOnly: boolean = false) { this.readOnly = readOnly; + if (json) { this.json = json; @@ -78,7 +81,7 @@ export class FormModel { return model; }); - this.fields = this.parseContainerFields(json); + this.fields = this.parseRootFields(json); if (data) { this.loadData(data); @@ -89,7 +92,6 @@ export class FormModel { if (field.tab) { let tab = tabCache[field.tab]; if (tab) { - // tab.fields.push(new ContainerModel(this, field.json)); tab.fields.push(field); } } @@ -112,18 +114,21 @@ export class FormModel { this.validateField(field); } - // TODO: evaluate and cache once the form is loaded - private getFormFields(): FormFieldModel[] { + // TODO: consider evaluating and caching once the form is loaded + getFormFields(): FormFieldModel[] { let result: FormFieldModel[] = []; for (let i = 0; i < this.fields.length; i++) { - let container = this.fields[i]; - for (let j = 0; j < container.columns.length; j++) { - let column = container.columns[j]; - for (let k = 0; k < column.fields.length; k++) { - let field = column.fields[k]; - result.push(field); - } + let field = this.fields[i]; + + if (field.type === FormFieldTypes.CONTAINER) { + let container = field; + result.push(...container.getFormFields()); + } + + if (field.type === FormFieldTypes.DYNAMIC_TABLE) { + let dynamicTable = field; + result.push(dynamicTable.field); } } @@ -152,7 +157,8 @@ export class FormModel { this.validateForm(); } - private parseContainerFields(json: any): ContainerModel[] { + // Activiti supports 2 types of root fields: 'container' and 'dynamic-table'. + private parseRootFields(json: any): FormWidgetModel[] { let fields = []; if (json.fields) { @@ -161,23 +167,26 @@ export class FormModel { fields = json.formDefinition.fields; } - return fields.map(obj => new ContainerModel(this, obj)); + let result: FormWidgetModel[] = []; + + for (let field of fields) { + if (field.type === FormFieldTypes.CONTAINER) { + result.push(new ContainerModel(this, field)); + } else if (field.type === FormFieldTypes.DYNAMIC_TABLE) { + result.push(new DynamicTableModel(this, field)); + } + } + + return result; } // Loads external data and overrides field values // Typically used when form definition and form data coming from different sources private loadData(data: FormValues) { - for (let i = 0; i < this.fields.length; i++) { - let container = this.fields[i]; - for (let i = 0; i < container.columns.length; i++) { - let column = container.columns[i]; - for (let i = 0; i < column.fields.length; i++) { - let field = column.fields[i]; - if (data[field.id]) { - field.json.value = data[field.id]; - field.value = data[field.id]; - } - } + for (let field of this.getFormFields()) { + if (data[field.id]) { + field.json.value = data[field.id]; + field.value = data[field.id]; } } } diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/index.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/index.ts index f2ba0588ae..2e2eecfb0b 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/index.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/index.ts @@ -28,3 +28,4 @@ export * from './tab.model'; export * from './form-outcome.model'; export * from './form-outcome-event.model'; export * from './form-field-validator'; +export * from './dynamic-table.model'; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/tab.model.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/tab.model.ts index aec92bef50..2a6945e076 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/tab.model.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/tab.model.ts @@ -16,7 +16,6 @@ */ import { FormWidgetModel } from './form-widget.model'; -import { ContainerModel } from './container.model'; import { FormModel } from './form.model'; import { WidgetVisibilityModel } from '../../../models/widget-visibility.model'; @@ -26,7 +25,7 @@ export class TabModel extends FormWidgetModel { isVisible: boolean = true; visibilityCondition: WidgetVisibilityModel; - fields: ContainerModel[] = []; + fields: FormWidgetModel[] = []; hasContent(): boolean { return this.fields && this.fields.length > 0; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.css b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.css new file mode 100644 index 0000000000..35ac21ae0d --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.css @@ -0,0 +1,19 @@ +.dynamic-table-widget { + width: 100%; +} + +.dynamic-table-widget__invalid .mdl-textfield__input { + border-color: #d50000; +} + +.dynamic-table-widget__invalid .mdl-textfield__label { + color: #d50000; +} + +.dynamic-table-widget__invalid .mdl-textfield__label:after { + background-color: #d50000; +} + +.dynamic-table-widget__invalid .mdl-textfield__error { + visibility: visible !important; +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.html b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.html new file mode 100644 index 0000000000..6e07c33c46 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.html @@ -0,0 +1,6 @@ +
+
{{field.name}}
+
DYNAMIC TABLE PLACEHOLDER
+ {{field.validationSummary}} +
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.ts new file mode 100644 index 0000000000..624cdc567d --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/dynamic-table.widget.ts @@ -0,0 +1,30 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component } from '@angular/core'; +import { WidgetComponent } from './../widget.component'; +// import { DynamicTableModel } from './../core/index'; + +@Component({ + moduleId: module.id, + selector: 'dynamic-table-widget', + templateUrl: './dynamic-table.widget.html', + styleUrls: ['./dynamic-table.widget.css'] +}) +export class DynamicTableWidget extends WidgetComponent { + +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/index.ts b/ng2-components/ng2-activiti-form/src/components/widgets/index.ts index 200ecf6631..78b3835020 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/index.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/index.ts @@ -34,6 +34,7 @@ import { FunctionalGroupWidget } from './functional-group/functional-group.widge import { PeopleWidget } from './people/people.widget'; import { DateWidget } from './date/date.widget'; import { AmountWidget } from './amount/amount.widget'; +import { DynamicTableWidget } from './dynamic-table/dynamic-table.widget'; // core export * from './widget.component'; @@ -60,6 +61,7 @@ export * from './functional-group/functional-group.widget'; export * from './people/people.widget'; export * from './date/date.widget'; export * from './amount/amount.widget'; +export * from './dynamic-table/dynamic-table.widget'; export const WIDGET_DIRECTIVES: any[] = [ TabsWidget, @@ -79,5 +81,6 @@ export const WIDGET_DIRECTIVES: any[] = [ FunctionalGroupWidget, PeopleWidget, DateWidget, - AmountWidget + AmountWidget, + DynamicTableWidget ]; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.html b/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.html index 4d9d3e7680..395ad7ddb0 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.html +++ b/ng2-components/ng2-activiti-form/src/components/widgets/tabs/tabs.widget.html @@ -12,10 +12,16 @@ class="mdl-tabs__panel" [class.is-active]="isFirst" [attr.id]="tab.id"> - - +
+
+
+ +
+
+ UNKNOWN WIDGET TYPE: {{field.type}} +
+
+
diff --git a/ng2-components/ng2-activiti-form/src/services/widget-visibility.service.ts b/ng2-components/ng2-activiti-form/src/services/widget-visibility.service.ts index 1b735ffa7e..aa8c3c9c16 100644 --- a/ng2-components/ng2-activiti-form/src/services/widget-visibility.service.ts +++ b/ng2-components/ng2-activiti-form/src/services/widget-visibility.service.ts @@ -37,12 +37,9 @@ export class WidgetVisibilityService { if (form && form.tabs && form.tabs.length > 0) { form.tabs.map(tabModel => this.refreshEntityVisibility(tabModel)); } - if (form && form.fields.length > 0) { - form.fields.map(contModel => { - this.refreshEntityVisibility(contModel); - contModel.columns.map(contColModel => - contColModel.fields.map(field => this.refreshEntityVisibility(field))); - }); + + if (form) { + form.getFormFields().map(field => this.refreshEntityVisibility(field)); } }