From 3fb0da0e0bba3859e833a2d67ff26c53f6d33a82 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 17 Oct 2016 11:45:58 +0100 Subject: [PATCH 01/17] Code improvements Move shared properties down to FormWidgetModel level, reduce repetitive parsing code. --- .../widgets/core/container.model.spec.ts | 7 +++- .../widgets/core/container.model.ts | 11 ----- .../widgets/core/form-field-types.ts | 1 + .../widgets/core/form-outcome.model.ts | 13 ------ .../widgets/core/form-widget.model.ts | 28 ++++++++----- .../src/components/widgets/core/form.model.ts | 41 +++++-------------- .../src/components/widgets/core/tab.model.ts | 2 - 7 files changed, 35 insertions(+), 68 deletions(-) diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/container.model.spec.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/container.model.spec.ts index 643929b392..7518e62e99 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/container.model.spec.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/container.model.spec.ts @@ -107,7 +107,12 @@ describe('ContainerModel', () => { }); expect(container.isCollapsible()).toBeFalsy(); - container.type = FormFieldTypes.GROUP; + container = new ContainerModel(new FormModel(), { + type: FormFieldTypes.GROUP, + params: { + allowCollapse: true + } + }); expect(container.isCollapsible()).toBeTruthy(); }); 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 bf6af192f4..e39acb78a0 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 @@ -23,14 +23,8 @@ import { FormModel } from './form.model'; import { FormFieldModel } from './form-field.model'; import { WidgetVisibilityModel } from '../../../models/widget-visibility.model'; -// TODO: inherit FormFieldModel export class ContainerModel extends FormWidgetModel { - fieldType: string; - id: string; - name: string; - type: string; - tab: string; numberOfColumns: number = 1; params: FormFieldMetadata = {}; isVisible: boolean = true; @@ -67,11 +61,6 @@ export class ContainerModel extends FormWidgetModel { super(form, json); if (json) { - this.fieldType = json.fieldType; - this.id = json.id; - this.name = json.name; - this.type = json.type; - this.tab = json.tab; this.numberOfColumns = json.numberOfColumns; this.params = json.params || {}; this.visibilityCondition = json.visibilityCondition; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-types.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-types.ts index f673b8cea3..9d0e23f5be 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-types.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-types.ts @@ -18,6 +18,7 @@ export class FormFieldTypes { static CONTAINER: string = 'container'; static GROUP: string = 'group'; + static DYNAMIC_TABLE: string = 'dynamic-table'; static TEXT: string = 'text'; static MULTILINE_TEXT: string = 'multi-line-text'; static DROPDOWN: string = 'dropdown'; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-outcome.model.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-outcome.model.ts index f0eb0abb05..219ddb7a41 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-outcome.model.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-outcome.model.ts @@ -23,25 +23,12 @@ export class FormOutcomeModel extends FormWidgetModel { static SAVE_ACTION: string = 'Save'; // Activiti 'Save' action name static COMPLETE_ACTION: string = 'Complete'; // Activiti 'Complete' action name - private _id: string; - private _name: string; - isSystem: boolean = false; - get id() { - return this._id; - } - - get name() { - return this._name; - } - constructor(form: FormModel, json?: any) { super(form, json); if (json) { - this._id = json.id; - this._name = json.name; this.isSystem = json.isSystem ? true : false; } } 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 39415c2547..f01ad71d5a 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 @@ -19,20 +19,26 @@ import { FormModel } from './form.model'; export class FormWidgetModel { - private _form: FormModel; - private _json: any; + readonly fieldType: string; + readonly id: string; + readonly name: string; + readonly type: string; + readonly tab: string; - get form(): FormModel { - return this._form; - } - - get json(): any { - return this._json; - } + readonly form: FormModel; + readonly json: any; constructor(form: FormModel, json: any) { - this._form = form; - this._json = json; + this.form = form; + this.json = json; + + if (json) { + this.fieldType = json.fieldType; + this.id = json.id; + this.name = json.name; + this.type = json.type; + this.tab = json.tab; + } } } 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 b3079ec4d6..878da23656 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 @@ -28,28 +28,13 @@ export class FormModel { static SAVE_OUTCOME: string = '$save'; static COMPLETE_OUTCOME: string = '$complete'; - private _id: string; - private _name: string; - private _taskId: string; - private _taskName: string = FormModel.UNSET_TASK_NAME; + readonly id: string; + readonly name: string; + readonly taskId: string; + readonly taskName: string = FormModel.UNSET_TASK_NAME; + private _isValid: boolean = true; - get id(): string { - return this._id; - } - - get name(): string { - return this._name; - } - - get taskId(): string { - return this._taskId; - } - - get taskName(): string { - return this._taskName; - } - get isValid(): boolean { return this._isValid; } @@ -61,11 +46,7 @@ export class FormModel { values: FormValues = {}; - private _json: any; - - get json() { - return this._json; - } + readonly json: any; hasTabs(): boolean { return this.tabs && this.tabs.length > 0; @@ -82,12 +63,12 @@ export class FormModel { constructor(json?: any, data?: FormValues, readOnly: boolean = false) { this.readOnly = readOnly; if (json) { - this._json = json; + this.json = json; - this._id = json.id; - this._name = json.name; - this._taskId = json.taskId; - this._taskName = json.taskName || json.name || FormModel.UNSET_TASK_NAME; + this.id = json.id; + this.name = json.name; + this.taskId = json.taskId; + this.taskName = json.taskName || json.name || FormModel.UNSET_TASK_NAME; let tabCache: FormWidgetModelCache = {}; 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 ccc0df7466..aec92bef50 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 @@ -22,7 +22,6 @@ import { WidgetVisibilityModel } from '../../../models/widget-visibility.model'; export class TabModel extends FormWidgetModel { - id: string; title: string; isVisible: boolean = true; visibilityCondition: WidgetVisibilityModel; @@ -37,7 +36,6 @@ export class TabModel extends FormWidgetModel { super(form, json); if (json) { - this.id = json.id; this.title = json.title; this.visibilityCondition = json.visibilityCondition; } From cf9053ab46d8ceb9b76014db1ac607621fbcba5c Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 17 Oct 2016 14:44:23 +0100 Subject: [PATCH 02/17] 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)); } } From 7a08a9d29df4f06710bef70f3bdd4d33a4242843 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 17 Oct 2016 16:10:49 +0100 Subject: [PATCH 03/17] Basic dynamic table rendering - render visible columns - code improvements --- .../components/activiti-form.component.html | 2 +- .../widgets/core/dynamic-table-column.ts | 48 +++++++++++++++++++ .../widgets/core/dynamic-table.model.ts | 11 +++++ .../dynamic-table/dynamic-table.widget.css | 4 ++ .../dynamic-table/dynamic-table.widget.html | 29 +++++++++-- .../dynamic-table/dynamic-table.widget.ts | 11 +++-- .../components/widgets/tabs/tabs.widget.html | 3 ++ 7 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-column.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 f3fcda7a3e..3d5d1d67b1 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 @@ -20,7 +20,7 @@
- +
UNKNOWN WIDGET TYPE: {{field.type}} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-column.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-column.ts new file mode 100644 index 0000000000..a5b4692f8f --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-column.ts @@ -0,0 +1,48 @@ +/*! + * @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. + */ + +// maps to: com.activiti.model.editor.form.ColumnDefinitionRepresentation +export interface DynamicTableColumn { + + id: string; + name: string; + type: string; + value: any; + optionType: string; + options: DynamicTableColumnOption[]; + restResponsePath: string; + restUrl: string; + restIdProperty: string; + restLabelProperty: string; + amountCurrency: string; + amountEnableFractions: boolean; + required: boolean; + editable: boolean; + sortable: boolean; + visible: boolean; + + // TODO: com.activiti.domain.idm.EndpointConfiguration.EndpointConfigurationRepresentation + endpoint: any; + // TODO: com.activiti.model.editor.form.RequestHeaderRepresentation + requestHeaders: any; +} + +// maps to: com.activiti.model.editor.form.OptionRepresentation +export interface DynamicTableColumnOption { + id: string; + name: string; +} 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 index 05115306a6..35411b5732 100644 --- 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 @@ -18,16 +18,27 @@ import { FormWidgetModel } from './form-widget.model'; import { FormModel } from './form.model'; import { FormFieldModel } from './form-field.model'; +import { DynamicTableColumn } from './dynamic-table-column'; export class DynamicTableModel extends FormWidgetModel { field: FormFieldModel; + columns: DynamicTableColumn[] = []; + visibleColumns: DynamicTableColumn[] = []; + rows: any[] = []; constructor(form: FormModel, json?: any) { super(form, json); if (json) { this.field = new FormFieldModel(form, json); + + if (json.columnDefinitions) { + this.columns = json.columnDefinitions.map(obj => obj); + this.visibleColumns = this.columns.filter(col => col.visible); + } + + this.rows = json.value || []; } } 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 index 35ac21ae0d..08af04f501 100644 --- 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 @@ -1,4 +1,8 @@ .dynamic-table-widget { + padding: 8px; +} + +.dynamic-table-widget__table { width: 100%; } 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 index 6e07c33c46..b747e57d55 100644 --- 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 @@ -1,6 +1,25 @@ -
-
{{field.name}}
-
DYNAMIC TABLE PLACEHOLDER
- {{field.validationSummary}} +
+
{{content.name}}
+ + + + + + + + + + + + +
+ {{column.name}} +
+ {{row[column.id]}} +
+ + {{content.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 index 624cdc567d..09898aa4a9 100644 --- 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 @@ -15,9 +15,9 @@ * limitations under the License. */ -import { Component } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { WidgetComponent } from './../widget.component'; -// import { DynamicTableModel } from './../core/index'; +import { DynamicTableModel } from './../core/index'; @Component({ moduleId: module.id, @@ -25,6 +25,11 @@ import { WidgetComponent } from './../widget.component'; templateUrl: './dynamic-table.widget.html', styleUrls: ['./dynamic-table.widget.css'] }) -export class DynamicTableWidget extends WidgetComponent { +export class DynamicTableWidget extends WidgetComponent implements OnInit { + @Input() + content: DynamicTableModel; + + ngOnInit() { + } } 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 395ad7ddb0..39664b5b7f 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 @@ -17,6 +17,9 @@
+
+ +
UNKNOWN WIDGET TYPE: {{field.type}}
From 8542999f0e4e85580ebe1114794ec6019a7bd7d1 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 17 Oct 2016 17:07:34 +0100 Subject: [PATCH 04/17] Selection state for dynamic table rows - visual indication of the selected row - toggling selection of the row --- .../widgets/core/dynamic-table-row.ts | 23 +++++++++++++++ .../widgets/core/dynamic-table.model.ts | 29 +++++++++++++++++-- .../src/components/widgets/core/index.ts | 2 ++ .../dynamic-table/dynamic-table.widget.css | 5 ++++ .../dynamic-table/dynamic-table.widget.html | 8 +++-- .../dynamic-table/dynamic-table.widget.ts | 8 ++++- 6 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-row.ts diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-row.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-row.ts new file mode 100644 index 0000000000..f6015e901b --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-row.ts @@ -0,0 +1,23 @@ +/*! + * @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. + */ + +export interface DynamicTableRow { + + selected: boolean; + value: any; + +} 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 index 35411b5732..88ca94ce66 100644 --- 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 @@ -19,13 +19,35 @@ import { FormWidgetModel } from './form-widget.model'; import { FormModel } from './form.model'; import { FormFieldModel } from './form-field.model'; import { DynamicTableColumn } from './dynamic-table-column'; +import { DynamicTableRow } from './dynamic-table-row'; export class DynamicTableModel extends FormWidgetModel { field: FormFieldModel; columns: DynamicTableColumn[] = []; visibleColumns: DynamicTableColumn[] = []; - rows: any[] = []; + rows: DynamicTableRow[] = []; + + private _selectedRow: DynamicTableRow; + + get selectedRow(): DynamicTableRow { + return this._selectedRow; + } + + set selectedRow(value: DynamicTableRow) { + if (this._selectedRow && this._selectedRow === value) { + this._selectedRow.selected = false; + this._selectedRow = null; + return; + } + + this.rows.forEach(row => row.selected = false); + + if (value) { + this._selectedRow = value; + this._selectedRow.selected = true; + } + } constructor(form: FormModel, json?: any) { super(form, json); @@ -38,8 +60,9 @@ export class DynamicTableModel extends FormWidgetModel { this.visibleColumns = this.columns.filter(col => col.visible); } - this.rows = json.value || []; + if (json.value) { + this.rows = json.value.map(obj => { selected: false, value: obj }); + } } } - } 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 2e2eecfb0b..902340e910 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 @@ -29,3 +29,5 @@ export * from './form-outcome.model'; export * from './form-outcome-event.model'; export * from './form-field-validator'; export * from './dynamic-table.model'; +export * from './dynamic-table-column'; +export * from './dynamic-table-row'; 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 index 08af04f501..7f133c4f0a 100644 --- 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 @@ -2,6 +2,11 @@ padding: 8px; } +.dynamic-table-widget__row-selected, +.dynamic-table-widget__row-selected:hover { + background-color: #eef !important; +} + .dynamic-table-widget__table { width: 100%; } 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 index b747e57d55..23ffd99b58 100644 --- 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 @@ -12,10 +12,12 @@ - + - {{row[column.id]}} + class="mdl-data-table__cell--non-numeric" + (click)="onRowClicked(row)"> + {{row.value[column.id]}} 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 index 09898aa4a9..b0eceaf07c 100644 --- 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 @@ -17,7 +17,7 @@ import { Component, Input, OnInit } from '@angular/core'; import { WidgetComponent } from './../widget.component'; -import { DynamicTableModel } from './../core/index'; +import { DynamicTableModel, DynamicTableRow } from './../core/index'; @Component({ moduleId: module.id, @@ -32,4 +32,10 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit { ngOnInit() { } + + onRowClicked(row: DynamicTableRow) { + if (this.content) { + this.content.selectedRow = row; + } + } } From 4f566a7ba2894dbc699d6cef6e207d9ad955f54d Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Thu, 20 Oct 2016 12:07:28 +0100 Subject: [PATCH 05/17] Move and delete rows (dynamic table) --- .../widgets/core/dynamic-table.model.ts | 41 ++++++++++++++++++- .../dynamic-table/dynamic-table.widget.html | 27 ++++++++++++ .../dynamic-table/dynamic-table.widget.ts | 30 ++++++++++++++ 3 files changed, 97 insertions(+), 1 deletion(-) 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 index 88ca94ce66..1ca9ae732d 100644 --- 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 @@ -43,8 +43,9 @@ export class DynamicTableModel extends FormWidgetModel { this.rows.forEach(row => row.selected = false); + this._selectedRow = value; + if (value) { - this._selectedRow = value; this._selectedRow.selected = true; } } @@ -65,4 +66,42 @@ export class DynamicTableModel extends FormWidgetModel { } } } + + flushValue() { + this.field.value = this.rows.map(r => r.value); + this.field.updateForm(); + } + + moveRow(row: DynamicTableRow, offset: number) { + let oldIndex = this.rows.indexOf(row); + if (oldIndex > -1) { + let newIndex = (oldIndex + offset); + + if (newIndex < 0) { + newIndex = 0; + } else if (newIndex >= this.rows.length) { + newIndex = this.rows.length; + } + + let arr = this.rows.slice(); + arr.splice(oldIndex, 1); + arr.splice(newIndex, 0, row); + this.rows = arr; + + this.flushValue(); + } + } + + deleteRow(row: DynamicTableRow) { + if (row) { + if (this.selectedRow === row) { + this.selectedRow = null; + } + let idx = this.rows.indexOf(row); + if (idx > -1) { + this.rows.splice(idx, 1); + this.flushValue(); + } + } + } } 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 index 23ffd99b58..799bc19d86 100644 --- 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 @@ -23,5 +23,32 @@ +
+ + + + + +
+ {{content.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 index b0eceaf07c..cab933f33a 100644 --- 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 @@ -38,4 +38,34 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit { this.content.selectedRow = row; } } + + hasSelection(): boolean { + return !!(this.content && this.content.selectedRow); + } + + moveSelectionUp() { + if (this.content) { + this.content.moveRow(this.content.selectedRow, -1); + } + } + + moveSelectionDown() { + if (this.content) { + this.content.moveRow(this.content.selectedRow, 1); + } + } + + addNewRow() { + console.log('add new row clicked'); + } + + deleteSelection() { + if (this.content) { + this.content.deleteRow(this.content.selectedRow); + } + } + + editSelection() { + console.log('edit selection clicked'); + } } From 51102980df913b53649ac757b4c8c38a86283b74 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 21 Oct 2016 16:32:10 +0100 Subject: [PATCH 06/17] Basic editing for dynamic table rows Editors: - text (also covers number and amount for now) - boolean - dropdown (manual) - date --- .../widgets/core/dynamic-table-row.ts | 1 + .../widgets/core/dynamic-table.model.ts | 20 +++ .../dynamic-table/dynamic-table.widget.css | 4 + .../dynamic-table/dynamic-table.widget.html | 143 ++++++++++++------ .../dynamic-table/dynamic-table.widget.ts | 71 ++++++++- .../editors/boolean/boolean.editor.css | 0 .../editors/boolean/boolean.editor.html | 9 ++ .../editors/boolean/boolean.editor.ts | 35 +++++ .../dynamic-table/editors/cell.editor.ts | 32 ++++ .../editors/date/date.editor.css | 7 + .../editors/date/date.editor.html | 21 +++ .../dynamic-table/editors/date/date.editor.ts | 74 +++++++++ .../editors/dropdown/dropdown.editor.css | 3 + .../editors/dropdown/dropdown.editor.html | 11 ++ .../editors/dropdown/dropdown.editor.ts | 36 +++++ .../editors/text/text.editor.css | 0 .../editors/text/text.editor.html | 9 ++ .../dynamic-table/editors/text/text.editor.ts | 35 +++++ .../src/components/widgets/index.ts | 17 ++- .../src/components/material/index.ts | 5 +- .../material/mdl-textfield.directive.ts | 38 +++++ 21 files changed, 513 insertions(+), 58 deletions(-) create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.css create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.html create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.ts create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/cell.editor.ts create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.css create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.html create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.ts create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.css create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.css create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.html create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.ts create mode 100644 ng2-components/ng2-alfresco-core/src/components/material/mdl-textfield.directive.ts diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-row.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-row.ts index f6015e901b..ce471b13b2 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-row.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/dynamic-table-row.ts @@ -17,6 +17,7 @@ export interface DynamicTableRow { + isNew: boolean; selected: boolean; value: any; 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 index 1ca9ae732d..65271329c1 100644 --- 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 @@ -104,4 +104,24 @@ export class DynamicTableModel extends FormWidgetModel { } } } + + getCellValue(row: DynamicTableRow, column: DynamicTableColumn): any { + let result = row.value[column.id]; + + if (column.type === 'Dropdown') { + return result.name; + } + + if (column.type === 'Boolean') { + return result ? true : false; + } + + if (column.type === 'Date') { + if (result) { + return moment(result.split('T')[0], 'YYYY-M-D').format('DD-MM-YYYY'); + } + } + + return result || ''; + } } 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 index 7f133c4f0a..58fad7d660 100644 --- 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 @@ -11,6 +11,10 @@ width: 100%; } +.dynamic-table-widget__table-editor { + width: 100%; +} + .dynamic-table-widget__invalid .mdl-textfield__input { border-color: #d50000; } 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 index 799bc19d86..8d4c92bb1e 100644 --- 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 @@ -1,54 +1,99 @@ -
+
{{content.name}}
- - - - - - - - - - - -
- {{column.name}} -
- {{row.value[column.id]}} -
+
+ + + + + + + + + + + +
+ {{column.name}} +
+ {{ getCellValue(row, column) }} +
-
- - - - - -
+
+ + + + + +
+
- {{content.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 index cab933f33a..6e8cc88ead 100644 --- 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 @@ -15,9 +15,9 @@ * limitations under the License. */ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit, ElementRef } from '@angular/core'; import { WidgetComponent } from './../widget.component'; -import { DynamicTableModel, DynamicTableRow } from './../core/index'; +import { DynamicTableModel, DynamicTableRow, DynamicTableColumn } from './../core/index'; @Component({ moduleId: module.id, @@ -30,6 +30,13 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit { @Input() content: DynamicTableModel; + editMode: boolean; + editRow: DynamicTableRow; + + constructor(private elementRef: ElementRef) { + super(); + } + ngOnInit() { } @@ -55,17 +62,67 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit { } } - addNewRow() { - console.log('add new row clicked'); - } - deleteSelection() { if (this.content) { this.content.deleteRow(this.content.selectedRow); } } + addNewRow() { + if (this.content) { + this.editRow = { selected: false, value: {} }; + this.editMode = true; + } + } + editSelection() { - console.log('edit selection clicked'); + if (this.content) { + this.editRow = this.copyRow(this.content.selectedRow); + this.editMode = true; + } + } + + getCellValue(row: DynamicTableRow, column: DynamicTableColumn): any { + if (this.content) { + return this.content.getCellValue(row, column); + } + return null; + } + + onSaveChanges() { + if (this.content) { + if (this.editRow.isNew) { + // TODO: create new record + } else { + this.content.selectedRow.value = this.copyObject(this.editRow.value); + } + this.content.flushValue(); + } + this.editMode = false; + } + + onCancelChanges() { + this.editMode = false; + this.editRow = null; + } + + private copyRow(row: DynamicTableRow): DynamicTableRow { + return { + value: this.copyObject(row.value) + }; + } + + private copyObject(obj: any): any { + let result = Object.assign({}, obj); + + if (typeof obj === 'object' && obj !== null && obj !== undefined) { + Object.keys(obj).forEach(key => { + if (typeof obj[key] === 'object') { + result[key] = this.copyObject(obj[key]); + } + }); + } + + return result; } } diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.css b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.html b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.html new file mode 100644 index 0000000000..88488cc509 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.html @@ -0,0 +1,9 @@ + diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.ts new file mode 100644 index 0000000000..8a322801d6 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.ts @@ -0,0 +1,35 @@ +/*! + * @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 { CellEditorComponent } from './../cell.editor'; +import { DynamicTableRow, DynamicTableColumn } from './../../../core/index'; + +@Component({ + moduleId: module.id, + selector: 'alf-boolean-editor', + templateUrl: './boolean.editor.html', + styleUrls: ['./boolean.editor.css'] +}) +export class BooleanEditorComponent extends CellEditorComponent { + + onValueChanged(row: DynamicTableRow, column: DynamicTableColumn, event: Event) { + let value: boolean = (event.srcElement).checked; + row.value[column.id] = value; + } + +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/cell.editor.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/cell.editor.ts new file mode 100644 index 0000000000..1ae25c438d --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/cell.editor.ts @@ -0,0 +1,32 @@ +/*! + * @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 { Input } from '@angular/core'; +import { DynamicTableModel, DynamicTableRow, DynamicTableColumn } from './../../core/index'; + +export abstract class CellEditorComponent { + + @Input() + table: DynamicTableModel; + + @Input() + row: DynamicTableRow; + + @Input() + column: DynamicTableColumn; + +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.css b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.css new file mode 100644 index 0000000000..9101330a83 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.css @@ -0,0 +1,7 @@ +.date-editor { + width: 100%; +} + +.date-editor--button { + margin-top: 15px; +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.html b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.html new file mode 100644 index 0000000000..64e481278c --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.html @@ -0,0 +1,21 @@ +
+
+
+ + +
+
+
+ +
+
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.ts new file mode 100644 index 0000000000..6fee69784a --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.ts @@ -0,0 +1,74 @@ +/*! + * @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, OnInit, ElementRef } from '@angular/core'; +import { CellEditorComponent } from './../cell.editor'; + +@Component({ + moduleId: module.id, + selector: 'alf-date-editor', + templateUrl: './date.editor.html', + styleUrls: ['./date.editor.css'] +}) +export class DateEditorComponent extends CellEditorComponent implements OnInit { + + DATE_FORMAT: string = 'DD-MM-YYYY'; + + datePicker: any; + + constructor(private elementRef: ElementRef) { + super(); + } + + ngOnInit() { + let settings: any = { + type: 'date', + future: moment().add(21, 'years'), + init: moment(this.table.getCellValue(this.row, this.column), this.DATE_FORMAT) + }; + + this.datePicker = new mdDateTimePicker.default(settings); + if (this.elementRef) { + this.datePicker.trigger = this.elementRef.nativeElement.querySelector('#dateInput'); + } + } + + onDateSelected(event: CustomEvent) { + let newValue = this.datePicker.time.format('YYYY-MM-DD'); + this.row.value[this.column.id] = newValue + 'T00:00:00.000Z'; + this.table.flushValue(); + + if (this.elementRef) { + this.setupMaterialTextField(this.elementRef, componentHandler, newValue); + } + } + + setupMaterialTextField(elementRef: ElementRef, handler: any, value: string): boolean { + if (elementRef && handler) { + let el = elementRef.nativeElement; + if (el) { + let container = el.querySelector('.mdl-textfield'); + if (container) { + container.MaterialTextfield.change(value); + return true; + } + } + } + return false; + } + +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.css b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.css new file mode 100644 index 0000000000..0db743bfa6 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.css @@ -0,0 +1,3 @@ +.dropdown-editor__select { + width: 100%; +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html new file mode 100644 index 0000000000..4d4fb3b4ab --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html @@ -0,0 +1,11 @@ +
+ +
+ +
+
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts new file mode 100644 index 0000000000..1adc51e220 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts @@ -0,0 +1,36 @@ +/*! + * @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 { CellEditorComponent } from './../cell.editor'; +import { DynamicTableRow, DynamicTableColumn } from './../../../core/index'; + +@Component({ + moduleId: module.id, + selector: 'alf-dropdown-editor', + templateUrl: './dropdown.editor.html', + styleUrls: ['./dropdown.editor.css'] +}) +export class DropdownEditorComponent extends CellEditorComponent { + + onValueChanged(row: DynamicTableRow, column: DynamicTableColumn, event: Event) { + let value: any = (event.srcElement).value; + value = column.options.find(opt => opt.name === value); + row.value[column.id] = value; + } + +} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.css b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.html b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.html new file mode 100644 index 0000000000..5c6ce90112 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.html @@ -0,0 +1,9 @@ +
+ + +
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.ts new file mode 100644 index 0000000000..3f57684ad9 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/text/text.editor.ts @@ -0,0 +1,35 @@ +/*! + * @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 { CellEditorComponent } from './../cell.editor'; +import { DynamicTableRow, DynamicTableColumn } from './../../../core/index'; + +@Component({ + moduleId: module.id, + selector: 'alf-text-editor', + templateUrl: './text.editor.html', + styleUrls: ['./text.editor.css'] +}) +export class TextEditorComponent extends CellEditorComponent { + + onValueChanged(row: DynamicTableRow, column: DynamicTableColumn, event: Event) { + let value: any = (event.srcElement).value; + row.value[column.id] = value; + } + +} 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 78b3835020..ddb8200b3e 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/index.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/index.ts @@ -35,6 +35,10 @@ 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'; +import { DateEditorComponent } from './dynamic-table/editors/date/date.editor'; +import { DropdownEditorComponent } from './dynamic-table/editors/dropdown/dropdown.editor'; +import { BooleanEditorComponent } from './dynamic-table/editors/boolean/boolean.editor'; +import { TextEditorComponent } from './dynamic-table/editors/text/text.editor'; // core export * from './widget.component'; @@ -63,6 +67,12 @@ export * from './date/date.widget'; export * from './amount/amount.widget'; export * from './dynamic-table/dynamic-table.widget'; +// editors (dynamic table) +export * from './dynamic-table/editors/date/date.editor'; +export * from './dynamic-table/editors/dropdown/dropdown.editor'; +export * from './dynamic-table/editors/boolean/boolean.editor'; +export * from './dynamic-table/editors/text/text.editor'; + export const WIDGET_DIRECTIVES: any[] = [ TabsWidget, ContainerWidget, @@ -82,5 +92,10 @@ export const WIDGET_DIRECTIVES: any[] = [ PeopleWidget, DateWidget, AmountWidget, - DynamicTableWidget + + DynamicTableWidget, + DateEditorComponent, + DropdownEditorComponent, + BooleanEditorComponent, + TextEditorComponent ]; diff --git a/ng2-components/ng2-alfresco-core/src/components/material/index.ts b/ng2-components/ng2-alfresco-core/src/components/material/index.ts index 8760c82be1..84f30ce07b 100644 --- a/ng2-components/ng2-alfresco-core/src/components/material/index.ts +++ b/ng2-components/ng2-alfresco-core/src/components/material/index.ts @@ -19,15 +19,18 @@ import { MDL } from './MaterialDesignLiteUpgradeElement'; import { AlfrescoMdlButtonDirective } from './mdl-button.directive'; import { AlfrescoMdlMenuDirective } from './mdl-menu.directive'; import { AlfrescoMdlTabsDirective } from './mdl-tabs.directive'; +import { AlfrescoMdlTextFieldDirective } from './mdl-textfield.directive'; export * from './MaterialDesignLiteUpgradeElement'; export * from './mdl-button.directive'; export * from './mdl-menu.directive'; export * from './mdl-tabs.directive'; +export * from './mdl-textfield.directive'; export const MATERIAL_DESIGN_DIRECTIVES: [any] = [ MDL, AlfrescoMdlButtonDirective, AlfrescoMdlMenuDirective, - AlfrescoMdlTabsDirective + AlfrescoMdlTabsDirective, + AlfrescoMdlTextFieldDirective ]; diff --git a/ng2-components/ng2-alfresco-core/src/components/material/mdl-textfield.directive.ts b/ng2-components/ng2-alfresco-core/src/components/material/mdl-textfield.directive.ts new file mode 100644 index 0000000000..d8e0a1be0b --- /dev/null +++ b/ng2-components/ng2-alfresco-core/src/components/material/mdl-textfield.directive.ts @@ -0,0 +1,38 @@ +/*! + * @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 { Directive, ElementRef, AfterViewInit } from '@angular/core'; + +declare var componentHandler; + +@Directive({ + selector: '[alfresco-mdl-textfield]' +}) +export class AlfrescoMdlTextFieldDirective implements AfterViewInit { + + constructor(private element: ElementRef) {} + + ngAfterViewInit() { + if (componentHandler) { + let el = this.element.nativeElement; + el.classList.add('mdl-textfield'); + el.classList.add('mdl-js-textfield'); + el.classList.add('mdl-textfield--floating-label'); + componentHandler.upgradeElement(el, 'MaterialTextfield'); + } + } +} From 36dd42b62d296f258eaf6838ce346a7f861d41e1 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Fri, 21 Oct 2016 17:16:04 +0100 Subject: [PATCH 07/17] Add new record (dynamic table) --- .../components/widgets/core/dynamic-table.model.ts | 11 ++++++++++- .../widgets/dynamic-table/dynamic-table.widget.ts | 11 +++++++++-- .../widgets/dynamic-table/editors/date/date.editor.ts | 8 ++++++-- .../editors/dropdown/dropdown.editor.html | 1 + 4 files changed, 26 insertions(+), 5 deletions(-) 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 index 65271329c1..7b4ec221dd 100644 --- 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 @@ -105,11 +105,20 @@ export class DynamicTableModel extends FormWidgetModel { } } + addRow(row: DynamicTableRow) { + if (row) { + this.rows.push(row); + // this.selectedRow = row; + } + } + getCellValue(row: DynamicTableRow, column: DynamicTableColumn): any { let result = row.value[column.id]; if (column.type === 'Dropdown') { - return result.name; + if (result) { + return result.name; + } } if (column.type === 'Boolean') { 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 index 6e8cc88ead..1969189bd6 100644 --- 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 @@ -70,7 +70,11 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit { addNewRow() { if (this.content) { - this.editRow = { selected: false, value: {} }; + this.editRow = { + isNew: true, + selected: false, + value: {} + }; this.editMode = true; } } @@ -92,7 +96,10 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit { onSaveChanges() { if (this.content) { if (this.editRow.isNew) { - // TODO: create new record + let row = this.copyRow(this.editRow); + this.content.selectedRow = null; + this.content.addRow(row); + this.editRow.isNew = false; } else { this.content.selectedRow.value = this.copyObject(this.editRow.value); } diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.ts index 6fee69784a..96293332b3 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.ts @@ -37,10 +37,14 @@ export class DateEditorComponent extends CellEditorComponent implements OnInit { ngOnInit() { let settings: any = { type: 'date', - future: moment().add(21, 'years'), - init: moment(this.table.getCellValue(this.row, this.column), this.DATE_FORMAT) + future: moment().add(21, 'years') }; + let value = this.table.getCellValue(this.row, this.column); + if (value) { + settings.init = moment(value, this.DATE_FORMAT); + } + this.datePicker = new mdDateTimePicker.default(settings); if (this.elementRef) { this.datePicker.trigger = this.elementRef.nativeElement.querySelector('#dateInput'); diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html index 4d4fb3b4ab..ed6589bc50 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html @@ -5,6 +5,7 @@ [value]="table.getCellValue(row, column)" class="dropdown-editor__select" (change)="onValueChanged(row, column, $event)"> +
From 3b898959ee27e03eebcc146d5ca35cb669d2afa2 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 24 Oct 2016 12:59:38 +0100 Subject: [PATCH 08/17] Support for rest dropdown fields (dynamic table) --- .../dynamic-table/dynamic-table.widget.html | 2 +- .../dynamic-table/editors/cell.editor.ts | 4 ++ .../editors/dropdown/dropdown.editor.html | 4 +- .../editors/dropdown/dropdown.editor.ts | 37 +++++++++++++++++-- .../src/services/form.service.ts | 7 +++- 5 files changed, 47 insertions(+), 7 deletions(-) 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 index 8d4c92bb1e..fd4f081758 100644 --- 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 @@ -51,7 +51,7 @@
-
+
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/cell.editor.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/cell.editor.ts index 1ae25c438d..c39ac33f77 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/cell.editor.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/cell.editor.ts @@ -29,4 +29,8 @@ export abstract class CellEditorComponent { @Input() column: DynamicTableColumn; + protected handleError(error: any) { + console.error(error); + } + } diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html index ed6589bc50..33f2045b1a 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html @@ -2,11 +2,11 @@
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts index 1adc51e220..afd0c0dbd2 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts @@ -15,9 +15,10 @@ * limitations under the License. */ -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { CellEditorComponent } from './../cell.editor'; -import { DynamicTableRow, DynamicTableColumn } from './../../../core/index'; +import { DynamicTableRow, DynamicTableColumn, DynamicTableColumnOption } from './../../../core/index'; +import { FormService } from './../../../../../services/form.service'; @Component({ moduleId: module.id, @@ -25,7 +26,36 @@ import { DynamicTableRow, DynamicTableColumn } from './../../../core/index'; templateUrl: './dropdown.editor.html', styleUrls: ['./dropdown.editor.css'] }) -export class DropdownEditorComponent extends CellEditorComponent { +export class DropdownEditorComponent extends CellEditorComponent implements OnInit { + + value: any; + options: DynamicTableColumnOption[] = []; + + constructor(private formService: FormService) { + super(); + } + + ngOnInit() { + this.value = this.table.getCellValue(this.row, this.column); + this.options = this.column.options || []; + + let field = this.table.field; + if (field && field.restUrl) { + this.formService + .getRestFieldValuesColumn( + field.form.taskId, + field.id, + this.column.id + ) + .subscribe( + (result: DynamicTableColumnOption[]) => { + this.column.options = result || []; + this.options = this.column.options; + }, + err => this.handleError(err) + ); + } + } onValueChanged(row: DynamicTableRow, column: DynamicTableColumn, event: Event) { let value: any = (event.srcElement).value; @@ -33,4 +63,5 @@ export class DropdownEditorComponent extends CellEditorComponent { row.value[column.id] = value; } + } diff --git a/ng2-components/ng2-activiti-form/src/services/form.service.ts b/ng2-components/ng2-activiti-form/src/services/form.service.ts index bcd020e02b..20311caacd 100644 --- a/ng2-components/ng2-activiti-form/src/services/form.service.ts +++ b/ng2-components/ng2-activiti-form/src/services/form.service.ts @@ -208,7 +208,12 @@ export class FormService { getRestFieldValues(taskId: string, field: string): Observable { let alfrescoApi = this.apiService.getInstance(); - return Observable.fromPromise(alfrescoApi.activiti.taskFormsApi.getRestFieldValues(taskId, field)); + return Observable.fromPromise(alfrescoApi.activiti.taskApi.getRestFieldValues(taskId, field)); + } + + getRestFieldValuesColumn(taskId: string, field: string, column?: string): Observable { + let alfrescoApi = this.apiService.getInstance(); + return Observable.fromPromise(alfrescoApi.activiti.taskApi.getRestFieldValuesColumn(taskId, field, column)); } // TODO: uses private webApp api From 3c0ad934776fb13707f968d91c136f5d5865b88f Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Mon, 24 Oct 2016 13:23:49 +0100 Subject: [PATCH 09/17] Fix code style --- .../widgets/dynamic-table/editors/dropdown/dropdown.editor.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts index afd0c0dbd2..c568f5420d 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.ts @@ -62,6 +62,4 @@ export class DropdownEditorComponent extends CellEditorComponent implements OnIn value = column.options.find(opt => opt.name === value); row.value[column.id] = value; } - - } From fe7b05df4f4d245367ccfeecaf3e9457eff9a06c Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 25 Oct 2016 11:49:43 +0100 Subject: [PATCH 10/17] Basic input validation (dynamic table) --- .../widgets/core/dynamic-table.model.ts | 112 ++++++++++++++++++ .../dynamic-table/dynamic-table.widget.css | 4 - .../dynamic-table/dynamic-table.widget.html | 51 ++------ .../dynamic-table/dynamic-table.widget.ts | 2 + .../editors/boolean/boolean.editor.html | 2 + .../editors/date/date.editor.html | 2 + .../editors/dropdown/dropdown.editor.html | 6 +- .../editors/dropdown/dropdown.editor.ts | 37 +++--- .../dynamic-table/editors/row.editor.css | 16 +++ .../dynamic-table/editors/row.editor.html | 45 +++++++ .../dynamic-table/editors/row.editor.ts | 73 ++++++++++++ .../editors/text/text.editor.css | 3 + .../editors/text/text.editor.html | 4 +- .../src/components/widgets/index.ts | 5 +- 14 files changed, 293 insertions(+), 69 deletions(-) create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/row.editor.css create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/row.editor.html create mode 100644 ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/row.editor.ts 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 index 7b4ec221dd..8c6e748848 100644 --- 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 @@ -29,6 +29,7 @@ export class DynamicTableModel extends FormWidgetModel { rows: DynamicTableRow[] = []; private _selectedRow: DynamicTableRow; + private _validators: CellValidator[] = []; get selectedRow(): DynamicTableRow { return this._selectedRow; @@ -65,6 +66,11 @@ export class DynamicTableModel extends FormWidgetModel { this.rows = json.value.map(obj => { selected: false, value: obj }); } } + + this._validators = [ + new RequiredCellValidator(), + new NumberCellValidator() + ]; } flushValue() { @@ -112,6 +118,25 @@ export class DynamicTableModel extends FormWidgetModel { } } + validateRow(row: DynamicTableRow): DynamicRowValidationSummary { + let summary = { + isValid: true, + text: null + }; + + if (row) { + for (let col of this.columns) { + for (let validator of this._validators) { + if (!validator.validate(row, col, summary)) { + return summary; + } + } + } + } + + return summary; + } + getCellValue(row: DynamicTableRow, column: DynamicTableColumn): any { let result = row.value[column.id]; @@ -134,3 +159,90 @@ export class DynamicTableModel extends FormWidgetModel { return result || ''; } } + +export interface DynamicRowValidationSummary { + + isValid: boolean; + text: string; + +} + +export interface CellValidator { + + isSupported(column: DynamicTableColumn): boolean; + validate(row: DynamicTableRow, column: DynamicTableColumn, summary?: DynamicRowValidationSummary): boolean; + +} + +export class RequiredCellValidator implements CellValidator { + + private supportedTypes: string[] = [ + 'String', + 'Number', + 'Amount', + 'Date', + 'Dropdown' + ]; + + isSupported(column: DynamicTableColumn): boolean { + return column && column.required && this.supportedTypes.indexOf(column.type) > -1; + } + + validate(row: DynamicTableRow, column: DynamicTableColumn, summary?: DynamicRowValidationSummary): boolean { + if (this.isSupported(column)) { + let value = row.value[column.id]; + if (column.required) { + if (value === null || value === undefined || value === '') { + if (summary) { + summary.isValid = false; + summary.text = `Field '${column.name}' is required.`; + } + return false; + } + } + } + + return true; + } + +} + +export class NumberCellValidator implements CellValidator { + + private supportedTypes: string[] = [ + 'Number', + 'Amount' + ]; + + isSupported(column: DynamicTableColumn): boolean { + return column && column.required && this.supportedTypes.indexOf(column.type) > -1; + } + + isNumber(value: any): boolean { + if (value === null || value === undefined || value === '') { + return false; + } + + return !isNaN(+value); + } + + validate(row: DynamicTableRow, column: DynamicTableColumn, summary?: DynamicRowValidationSummary): boolean { + + if (this.isSupported(column)) { + let value = row.value[column.id]; + if (value === null || + value === undefined || + value === '' || + this.isNumber(value)) { + return true; + } + + if (summary) { + summary.isValid = false; + summary.text = `Field '${column.name}' must be a number.`; + } + return false; + } + return true; + } +} 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 index 58fad7d660..7f133c4f0a 100644 --- 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 @@ -11,10 +11,6 @@ width: 100%; } -.dynamic-table-widget__table-editor { - width: 100%; -} - .dynamic-table-widget__invalid .mdl-textfield__input { border-color: #d50000; } 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 index fd4f081758..dd39213e6c 100644 --- 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 @@ -51,49 +51,12 @@
-
-
-
-
- - -
-
- - -
+ + -
- - -
-
- - -
-
-
-
- - -
-
- -
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 index 1969189bd6..2eeddbc277 100644 --- 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 @@ -32,12 +32,14 @@ export class DynamicTableWidget extends WidgetComponent implements OnInit { editMode: boolean; editRow: DynamicTableRow; + validationSummary: string; constructor(private elementRef: ElementRef) { super(); } ngOnInit() { + this.validationSummary = 'hello world'; } onRowClicked(row: DynamicTableRow) { diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.html b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.html index 88488cc509..b92d6f30ba 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.html +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/boolean/boolean.editor.html @@ -4,6 +4,8 @@ type="checkbox" [attr.id]="column.id" [checked]="table.getCellValue(row, column)" + [required]="column.required" + [disabled]="!column.editable" (change)="onValueChanged(row, column, $event)"> {{column.name}} diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.html b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.html index 64e481278c..b4beaa2463 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.html +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/date/date.editor.html @@ -7,6 +7,8 @@ [value]="table.getCellValue(row, column)" [attr.id]="column.id" [readonly]="true" + [required]="column.required" + [disabled]="!column.editable" (onOk)="onDateSelected($event)">
diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html index 33f2045b1a..026f9cd555 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html +++ b/ng2-components/ng2-activiti-form/src/components/widgets/dynamic-table/editors/dropdown/dropdown.editor.html @@ -1,9 +1,11 @@ -
+