diff --git a/demo-shell-ng2/app/components/form/demo-form.ts b/demo-shell-ng2/app/components/form/demo-form.ts index 5e58ce8e5b..a496247fac 100644 --- a/demo-shell-ng2/app/components/form/demo-form.ts +++ b/demo-shell-ng2/app/components/form/demo-form.ts @@ -2,14 +2,14 @@ * @license * Copyright 2016 Alfresco Software, Ltd. * - * Licensed under the Apache License, Version 2.0 (the "License"); + * 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, + * 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. @@ -17,6 +17,343 @@ export class DemoForm { + static getEasyForm(): any { + return { + 'id': 1001, + 'name': 'ISSUE_FORM', + 'processDefinitionId': 'ISSUE_APP:1:2504', + 'processDefinitionName': 'ISSUE_APP', + 'processDefinitionKey': 'ISSUE_APP', + 'taskId': '2510', + 'taskDefinitionKey': 'sid-F67A2996-1684-4774-855A-4591490081FD', + 'tabs': [], + 'fields': [ + { + 'fieldType': 'ContainerRepresentation', + 'id': '1498212398417', + 'name': 'Label', + 'type': 'container', + 'value': null, + 'required': false, + 'readOnly': false, + 'overrideId': false, + 'colspan': 1, + 'placeholder': null, + 'minLength': 0, + 'maxLength': 0, + 'minValue': null, + 'maxValue': null, + 'regexPattern': null, + 'optionType': null, + 'hasEmptyValue': false, + 'options': null, + 'restUrl': null, + 'restResponsePath': null, + 'restIdProperty': null, + 'restLabelProperty': null, + 'tab': null, + 'className': null, + 'dateDisplayFormat': null, + 'sizeX': 2, + 'sizeY': 1, + 'row': -1, + 'col': -1, + 'numberOfColumns': 2, + 'fields': { + '1': [ + { + 'fieldType': 'RestFieldRepresentation', + 'id': 'label', + 'name': 'Label', + 'type': 'dropdown', + 'value': 'Choose one...', + 'required': false, + 'readOnly': false, + 'overrideId': false, + 'colspan': 1, + 'placeholder': null, + 'minLength': 0, + 'maxLength': 0, + 'minValue': null, + 'maxValue': null, + 'regexPattern': null, + 'optionType': null, + 'hasEmptyValue': true, + 'options': [ + { + 'id': 'empty', + 'name': 'Choose one...' + }, + { + 'id': 'option_1', + 'name': 'test1' + }, + { + 'id': 'option_2', + 'name': 'test2' + }, + { + 'id': 'option_3', + 'name': 'test3' + } + ], + 'restUrl': null, + 'restResponsePath': null, + 'restIdProperty': null, + 'restLabelProperty': null, + 'tab': null, + 'className': null, + 'params': { + 'existingColspan': 1, + 'maxColspan': 2 + }, + 'dateDisplayFormat': null, + 'layout': { + 'row': -1, + 'column': -1, + 'colspan': 1 + }, + 'sizeX': 1, + 'sizeY': 1, + 'row': -1, + 'col': -1, + 'visibilityCondition': null, + 'endpoint': null, + 'requestHeaders': null + }, + { + 'fieldType': 'FormFieldRepresentation', + 'id': 'Date', + 'name': 'Date', + 'type': 'date', + 'value': null, + 'required': false, + 'readOnly': false, + 'overrideId': false, + 'colspan': 1, + 'placeholder': null, + 'minLength': 0, + 'maxLength': 0, + 'minValue': null, + 'maxValue': null, + 'regexPattern': null, + 'optionType': null, + 'hasEmptyValue': null, + 'options': null, + 'restUrl': null, + 'restResponsePath': null, + 'restIdProperty': null, + 'restLabelProperty': null, + 'tab': 'tab1', + 'className': null, + 'params': { + 'existingColspan': 1, + 'maxColspan': 2 + }, + 'dateDisplayFormat': null, + 'layout': { + 'row': -1, + 'column': -1, + 'colspan': 1 + }, + 'sizeX': 1, + 'sizeY': 1, + 'row': -1, + 'col': -1, + 'visibilityCondition': null + }, + { + 'fieldType': 'FormFieldRepresentation', + 'id': 'label5', + 'name': 'Label5', + 'type': 'boolean', + 'value': null, + 'required': false, + 'readOnly': false, + 'overrideId': false, + 'colspan': 1, + 'placeholder': null, + 'minLength': 0, + 'maxLength': 0, + 'minValue': null, + 'maxValue': null, + 'regexPattern': null, + 'optionType': null, + 'hasEmptyValue': null, + 'options': null, + 'restUrl': null, + 'restResponsePath': null, + 'restIdProperty': null, + 'restLabelProperty': null, + 'tab': 'tab1', + 'className': null, + 'params': { + 'existingColspan': 1, + 'maxColspan': 1 + }, + 'dateDisplayFormat': null, + 'layout': { + 'row': -1, + 'column': -1, + 'colspan': 1 + }, + 'sizeX': 1, + 'sizeY': 1, + 'row': -1, + 'col': -1, + 'visibilityCondition': null + }, + { + 'fieldType': 'FormFieldRepresentation', + 'id': 'label6', + 'name': 'Label6', + 'type': 'boolean', + 'value': null, + 'required': false, + 'readOnly': false, + 'overrideId': false, + 'colspan': 1, + 'placeholder': null, + 'minLength': 0, + 'maxLength': 0, + 'minValue': null, + 'maxValue': null, + 'regexPattern': null, + 'optionType': null, + 'hasEmptyValue': null, + 'options': null, + 'restUrl': null, + 'restResponsePath': null, + 'restIdProperty': null, + 'restLabelProperty': null, + 'tab': 'tab1', + 'className': null, + 'params': { + 'existingColspan': 1, + 'maxColspan': 1 + }, + 'dateDisplayFormat': null, + 'layout': { + 'row': -1, + 'column': -1, + 'colspan': 1 + }, + 'sizeX': 1, + 'sizeY': 1, + 'row': -1, + 'col': -1, + 'visibilityCondition': null + }, + { + 'fieldType': 'FormFieldRepresentation', + 'id': 'label4', + 'name': 'Label4', + 'type': 'integer', + 'value': null, + 'required': false, + 'readOnly': false, + 'overrideId': false, + 'colspan': 1, + 'placeholder': null, + 'minLength': 0, + 'maxLength': 0, + 'minValue': null, + 'maxValue': null, + 'regexPattern': null, + 'optionType': null, + 'hasEmptyValue': null, + 'options': null, + 'restUrl': null, + 'restResponsePath': null, + 'restIdProperty': null, + 'restLabelProperty': null, + 'tab': 'tab1', + 'className': null, + 'params': { + 'existingColspan': 1, + 'maxColspan': 2 + }, + 'dateDisplayFormat': null, + 'layout': { + 'row': -1, + 'column': -1, + 'colspan': 1 + }, + 'sizeX': 1, + 'sizeY': 1, + 'row': -1, + 'col': -1, + 'visibilityCondition': null + }, + { + 'fieldType': 'RestFieldRepresentation', + 'id': 'label12', + 'name': 'Label12', + 'type': 'radio-buttons', + 'value': null, + 'required': false, + 'readOnly': false, + 'overrideId': false, + 'colspan': 1, + 'placeholder': null, + 'minLength': 0, + 'maxLength': 0, + 'minValue': null, + 'maxValue': null, + 'regexPatt§12212ern': null, + 'optionType': null, + 'hasEmptyValue': null, + 'options': [ + { + 'id': 'option_1', + 'name': 'Option 1' + }, + { + 'id': 'option_2', + 'name': 'Option 2' + } + ], + 'restUrl': null, + 'restResponsePath': null, + 'restIdProperty': null, + 'restLabelProperty': null, + 'tab': 'tab1', + 'className': null, + 'params': { + 'existingColspan': 1, + 'maxColspan': 2 + }, + 'dateDisplayFormat': null, + 'layout': { + 'row': -1, + 'column': -1, + 'colspan': 1 + }, + 'sizeX': 1, + 'sizeY': 1, + 'row': -1, + 'col': -1, + 'visibilityCondition': null, + 'endpoint': null, + 'requestHeaders': null + } + ] + } + } + ], + 'outcomes': [], + 'javascriptEvents': [], + 'className': '', + 'style': '', + 'customFieldTemplates': {}, + 'metadata': {}, + 'variables': [], + 'customFieldsValueInfo': {}, + 'gridsterForm': false, + 'globalDateFormat': 'D-M-YYYY' + }; + } + static getDefinition(): any { return { 'id': 3003, diff --git a/demo-shell-ng2/app/components/form/form-demo.component.css b/demo-shell-ng2/app/components/form/form-demo.component.css index 3608df8b91..ee6f7a61fb 100644 --- a/demo-shell-ng2/app/components/form/form-demo.component.css +++ b/demo-shell-ng2/app/components/form/form-demo.component.css @@ -1,3 +1,8 @@ .form-container { padding: 10px; } + +.store-form-container{ + width: 80%; + height: 80%; +} diff --git a/demo-shell-ng2/app/components/form/form-demo.component.html b/demo-shell-ng2/app/components/form/form-demo.component.html index 8193f015fe..5b993a273c 100644 --- a/demo-shell-ng2/app/components/form/form-demo.component.html +++ b/demo-shell-ng2/app/components/form/form-demo.component.html @@ -1,4 +1,32 @@ -
- - +
+
+
+ DEMO + STORE +
+
+
+
+
+ + +
+
+
+ FORM NAME TO VISUALIZE + +
+ + + + +
+
+ Please create in APS the form with the name you entered +
+
+ Form Name not valid or form not present +
+
+
diff --git a/demo-shell-ng2/app/components/form/form-demo.component.ts b/demo-shell-ng2/app/components/form/form-demo.component.ts index 5ad24ab3f4..9ba8d6e2bc 100644 --- a/demo-shell-ng2/app/components/form/form-demo.component.ts +++ b/demo-shell-ng2/app/components/form/form-demo.component.ts @@ -15,9 +15,12 @@ * limitations under the License. */ -import { Component, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core'; import { FormModel, FormService } from 'ng2-activiti-form'; import { DemoForm } from './demo-form'; +import { ActivitiForm } from 'ng2-activiti-form'; + +declare var componentHandler; @Component({ selector: 'form-demo', @@ -26,9 +29,17 @@ import { DemoForm } from './demo-form'; 'form-demo.component.css' ] }) -export class FormDemoComponent implements OnInit { +export class FormDemoComponent implements OnInit, AfterViewInit { + + @ViewChild(ActivitiForm) + activitiForm: ActivitiForm; form: FormModel; + activeTab: string = 'demo'; + storedData: any = {}; + restoredData: any = {}; + formToLoadName: string = null; + showError: boolean = false; constructor(private formService: FormService) { formService.executeOutcome.subscribe(e => { @@ -43,4 +54,69 @@ export class FormDemoComponent implements OnInit { console.log(form); this.form = form; } + + ngAfterViewInit() { + // workaround for MDL issues with dynamic components + if (componentHandler) { + componentHandler.upgradeAllRegistered(); + } + } + + changeToStoreForm() { + this.activeTab = 'store'; + this.showError = false; + } + + changeToDemoForm() { + this.activeTab = 'demo'; + let formDefinitionJSON: any = DemoForm.getDefinition(); + let demoForm = this.formService.parseForm(formDefinitionJSON); + this.form = demoForm; + } + + store() { + this.clone(this.activitiForm.form.values, this.storedData); + console.log('DATA SAVED'); + console.log(this.storedData); + console.log('DATA SAVED'); + this.restoredData = null; + } + + restore() { + this.restoredData = this.storedData; + this.storedData = {}; + } + + clone(objToCopyFrom, objToCopyTo) { + for (let attribute in objToCopyFrom) { + if (objToCopyFrom.hasOwnProperty(attribute)) { + objToCopyTo[attribute] = objToCopyFrom[attribute]; + } + } + return objToCopyTo; + } + + loadForm() { + if (this.formToLoadName) { + this.showError = false; + this.formService + .getFormDefinitionByName(this.formToLoadName) + .debounceTime(7000) + .subscribe( + id => { + this.formService.getFormDefinitionById(id).subscribe( + form => { + this.form = this.formService.parseForm((form); + }, + (error) => { + this.showError = true; + } + ); + }, + (error) => { + this.showError = true; + } + ); + } + } } diff --git a/ng2-components/ng2-activiti-form/README.md b/ng2-components/ng2-activiti-form/README.md index 2877e84f06..dc8c339051 100644 --- a/ng2-components/ng2-activiti-form/README.md +++ b/ng2-components/ng2-activiti-form/README.md @@ -174,13 +174,14 @@ The recommended set of properties can be found in the following table: ### Events -| Name | Description | -| --- | --- | -| formLoaded | Invoked when form is loaded or reloaded. | -| formSaved | Invoked when form is submitted with `Save` or custom outcomes. | -| formCompleted | Invoked when form is submitted with `Complete` outcome. | -| executeOutcome | Invoked when any outcome is executed, default behaviour can be prevented via `event.preventDefault()` | -| onError | Invoked at any error | +| Name | Return Type | Description | +| --- | --- | --- | +| formLoaded | [FormModel](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.ts) | Invoked when form is loaded or reloaded. | +| formSaved | [FormModel](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.ts) | Invoked when form is submitted with `Save` or custom outcomes. | +| formCompleted | [FormModel](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.ts) | Invoked when form is submitted with `Complete` outcome. | +| formDataRefreshed | [FormModel](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-activiti-form/src/components/widgets/core/form.model.ts) | Invoked when form values are refreshed due a data property change | +| executeOutcome | [FormOutcomeEvent](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-activiti-form/src/components/widgets/core/form-outcome-event.model.ts) | Invoked when any outcome is executed, default behaviour can be prevented via `event.preventDefault()` | +| onError | any | Invoked at any error | All `form*` events receive an instance of the `FormModel` as event argument for ease of development: diff --git a/ng2-components/ng2-activiti-form/src/assets/activiti-form.component.mock.ts b/ng2-components/ng2-activiti-form/src/assets/activiti-form.component.mock.ts new file mode 100644 index 0000000000..64080265a7 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/assets/activiti-form.component.mock.ts @@ -0,0 +1,275 @@ +/*! + * @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 let fakeForm = { + id: 1001, + name: 'ISSUE_FORM', + processDefinitionId: 'ISSUE_APP:1:2504', + processDefinitionName: 'ISSUE_APP', + processDefinitionKey: 'ISSUE_APP', + taskId: '7506', + taskDefinitionKey: 'sid-F67A2996-1684-4774-855A-4591490081FD', + tabs: [], + fields: [ + { + fieldType: 'ContainerRepresentation', + id: '1498212398417', + name: 'Label', + type: 'container', + value: null, + required: false, + readOnly: false, + overrideId: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + minValue: null, + maxValue: null, + regexPattern: null, + optionType: null, + hasEmptyValue: null, + options: null, + restUrl: null, + restResponsePath: null, + restIdProperty: null, + restLabelProperty: null, + tab: null, + className: null, + dateDisplayFormat: null, + layout: null, + sizeX: 2, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: null, + numberOfColumns: 2, + fields: { + 1: [ + { + fieldType: 'RestFieldRepresentation', + id: 'label', + name: 'Label', + type: 'dropdown', + value: 'Choose one...', + required: false, + readOnly: false, + overrideId: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + minValue: null, + maxValue: null, + regexPattern: null, + optionType: null, + hasEmptyValue: true, + options: [ + { + id: 'empty', + name: 'Choose one...' + }, + { + id: 'option_1', + name: 'test1' + }, + { + id: 'option_2', + name: 'test2' + }, + { + id: 'option_3', + name: 'test3' + } + ], + restUrl: null, + restResponsePath: null, + restIdProperty: null, + restLabelProperty: null, + tab: null, + className: null, + params: { + existingColspan: 1, + maxColspan: 2 + }, + dateDisplayFormat: null, + layout: { + row: -1, + column: -1, + colspan: 1 + }, + sizeX: 1, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: null, + endpoint: null, + requestHeaders: null + } + ], + 2: [ + { + fieldType: 'RestFieldRepresentation', + id: 'raduio', + name: 'raduio', + type: 'radio-buttons', + value: null, + required: false, + readOnly: false, + overrideId: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + minValue: null, + maxValue: null, + regexPattern: null, + optionType: null, + hasEmptyValue: null, + options: [ + { + id: 'option_1', + name: 'Option 1' + }, + { + id: 'option_2', + name: 'Option 2' + }, + { + id: 'option_3', + name: 'Option 3' + } + ], + restUrl: null, + restResponsePath: null, + restIdProperty: null, + restLabelProperty: null, + tab: null, + className: null, + params: { + existingColspan: 1, + maxColspan: 1 + }, + dateDisplayFormat: null, + layout: { + row: -1, + column: -1, + colspan: 1 + }, + sizeX: 1, + sizeY: 2, + row: -1, + col: -1, + visibilityCondition: null, + endpoint: null, + requestHeaders: null + } + ] + } + }, + { + fieldType: 'ContainerRepresentation', + id: '1498212413062', + name: 'Label', + type: 'container', + value: null, + required: false, + readOnly: false, + overrideId: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + minValue: null, + maxValue: null, + regexPattern: null, + optionType: null, + hasEmptyValue: null, + options: null, + restUrl: null, + restResponsePath: null, + restIdProperty: null, + restLabelProperty: null, + tab: null, + className: null, + dateDisplayFormat: null, + layout: null, + sizeX: 2, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: null, + numberOfColumns: 2, + fields: { + 1: [ + { + fieldType: 'FormFieldRepresentation', + id: 'date', + name: 'date', + type: 'date', + value: null, + required: false, + readOnly: false, + overrideId: false, + colspan: 1, + placeholder: null, + minLength: 0, + maxLength: 0, + minValue: null, + maxValue: null, + regexPattern: null, + optionType: null, + hasEmptyValue: null, + options: null, + restUrl: null, + restResponsePath: null, + restIdProperty: null, + restLabelProperty: null, + tab: null, + className: null, + params: { + existingColspan: 1, + maxColspan: 2 + }, + dateDisplayFormat: null, + layout: { + row: -1, + column: -1, + colspan: 1 + }, + sizeX: 1, + sizeY: 1, + row: -1, + col: -1, + visibilityCondition: null + } + ], + 2: [] + } + } + ], + outcomes: [], + javascriptEvents: [], + className: '', + style: '', + customFieldTemplates: {}, + metadata: {}, + variables: [], + customFieldsValueInfo: {}, + gridsterForm: false, + globalDateFormat: 'D-M-YYYY' +}; 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 d1d6c42bdb..931c36ced2 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 @@ -23,6 +23,7 @@ import { FormModel, FormOutcomeModel, FormFieldModel, FormOutcomeEvent, FormFiel import { FormService } from './../services/form.service'; import { WidgetVisibilityService } from './../services/widget-visibility.service'; import { NodeService } from './../services/node.service'; +import { fakeForm } from '../assets/activiti-form.component.mock'; describe('ActivitiForm', () => { @@ -107,14 +108,14 @@ describe('ActivitiForm', () => { it('should enable custom outcome buttons', () => { let formModel = new FormModel(); formComponent.form = formModel; - let outcome = new FormOutcomeModel(formModel, {id: 'action1', name: 'Action 1'}); + let outcome = new FormOutcomeModel(formModel, { id: 'action1', name: 'Action 1' }); expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy(); }); it('should allow controlling [complete] button visibility', () => { let formModel = new FormModel(); formComponent.form = formModel; - let outcome = new FormOutcomeModel(formModel, {id: '$save', name: FormOutcomeModel.SAVE_ACTION}); + let outcome = new FormOutcomeModel(formModel, { id: '$save', name: FormOutcomeModel.SAVE_ACTION }); formComponent.showSaveButton = true; expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy(); @@ -127,7 +128,7 @@ describe('ActivitiForm', () => { let formModel = new FormModel(); formModel.readOnly = true; formComponent.form = formModel; - let outcome = new FormOutcomeModel(formModel, {id: '$complete', name: FormOutcomeModel.COMPLETE_ACTION}); + let outcome = new FormOutcomeModel(formModel, { id: '$complete', name: FormOutcomeModel.COMPLETE_ACTION }); formComponent.showCompleteButton = true; expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy(); @@ -137,23 +138,23 @@ describe('ActivitiForm', () => { let formModel = new FormModel(); formModel.readOnly = true; formComponent.form = formModel; - let outcome = new FormOutcomeModel(formModel, {id: '$save', name: FormOutcomeModel.SAVE_ACTION}); + let outcome = new FormOutcomeModel(formModel, { id: '$save', name: FormOutcomeModel.SAVE_ACTION }); formComponent.showSaveButton = true; expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeFalsy(); }); it('should show [custom-outcome] button with readOnly form and selected custom-outcome', () => { - let formModel = new FormModel({selectedOutcome: 'custom-outcome'}); + let formModel = new FormModel({ selectedOutcome: 'custom-outcome' }); formModel.readOnly = true; formComponent.form = formModel; - let outcome = new FormOutcomeModel(formModel, {id: '$customoutome', name: 'custom-outcome'}); + let outcome = new FormOutcomeModel(formModel, { id: '$customoutome', name: 'custom-outcome' }); formComponent.showCompleteButton = true; formComponent.showSaveButton = true; expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy(); - outcome = new FormOutcomeModel(formModel, {id: '$customoutome2', name: 'custom-outcome2'}); + outcome = new FormOutcomeModel(formModel, { id: '$customoutome2', name: 'custom-outcome2' }); expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeFalsy(); }); @@ -161,7 +162,7 @@ describe('ActivitiForm', () => { let formModel = new FormModel(); formModel.readOnly = false; formComponent.form = formModel; - let outcome = new FormOutcomeModel(formModel, {id: '$save', name: FormOutcomeModel.COMPLETE_ACTION}); + let outcome = new FormOutcomeModel(formModel, { id: '$save', name: FormOutcomeModel.COMPLETE_ACTION }); formComponent.showCompleteButton = true; expect(formComponent.isOutcomeButtonVisible(outcome, formComponent.form.readOnly)).toBeTruthy(); @@ -191,7 +192,7 @@ describe('ActivitiForm', () => { it('should get process variable if is a process task', () => { spyOn(formService, 'getTaskForm').and.callFake((taskId) => { return Observable.create(observer => { - observer.next({taskId: taskId}); + observer.next({ taskId: taskId }); observer.complete(); }); }); @@ -199,7 +200,7 @@ describe('ActivitiForm', () => { spyOn(visibilityService, 'getTaskProcessVariable').and.returnValue(Observable.of({})); spyOn(formService, 'getTask').and.callFake((taskId) => { return Observable.create(observer => { - observer.next({taskId: taskId, processDefinitionId: '10201'}); + observer.next({ taskId: taskId, processDefinitionId: '10201' }); observer.complete(); }); }); @@ -214,7 +215,7 @@ describe('ActivitiForm', () => { it('should not get process variable if is not a process task', () => { spyOn(formService, 'getTaskForm').and.callFake((taskId) => { return Observable.create(observer => { - observer.next({taskId: taskId}); + observer.next({ taskId: taskId }); observer.complete(); }); }); @@ -222,7 +223,7 @@ describe('ActivitiForm', () => { spyOn(visibilityService, 'getTaskProcessVariable').and.returnValue(Observable.of({})); spyOn(formService, 'getTask').and.callFake((taskId) => { return Observable.create(observer => { - observer.next({taskId: taskId, processDefinitionId: 'null'}); + observer.next({ taskId: taskId, processDefinitionId: 'null' }); observer.complete(); }); }); @@ -259,7 +260,7 @@ describe('ActivitiForm', () => { const taskId = ''; let change = new SimpleChange(null, taskId, true); - formComponent.ngOnChanges({'taskId': change}); + formComponent.ngOnChanges({ 'taskId': change }); expect(formComponent.getFormByTaskId).toHaveBeenCalledWith(taskId); }); @@ -269,7 +270,7 @@ describe('ActivitiForm', () => { const formId = '123'; let change = new SimpleChange(null, formId, true); - formComponent.ngOnChanges({'formId': change}); + formComponent.ngOnChanges({ 'formId': change }); expect(formComponent.getFormDefinitionByFormId).toHaveBeenCalledWith(formId); }); @@ -279,7 +280,7 @@ describe('ActivitiForm', () => { const formName = '
'; let change = new SimpleChange(null, formName, true); - formComponent.ngOnChanges({'formName': change}); + formComponent.ngOnChanges({ 'formName': change }); expect(formComponent.getFormDefinitionByFormName).toHaveBeenCalledWith(formName); }); @@ -304,7 +305,7 @@ describe('ActivitiForm', () => { spyOn(formComponent, 'getFormDefinitionByFormId').and.stub(); spyOn(formComponent, 'getFormDefinitionByFormName').and.stub(); - formComponent.ngOnChanges({'tag': new SimpleChange(null, 'hello world', true)}); + formComponent.ngOnChanges({ 'tag': new SimpleChange(null, 'hello world', true) }); expect(formComponent.getFormByTaskId).not.toHaveBeenCalled(); expect(formComponent.getFormDefinitionByFormId).not.toHaveBeenCalled(); @@ -314,7 +315,7 @@ describe('ActivitiForm', () => { it('should complete form on custom outcome click', () => { let formModel = new FormModel(); let outcomeName = 'Custom Action'; - let outcome = new FormOutcomeModel(formModel, {id: 'custom1', name: outcomeName}); + let outcome = new FormOutcomeModel(formModel, { id: 'custom1', name: outcomeName }); let saved = false; formComponent.form = formModel; @@ -379,7 +380,7 @@ describe('ActivitiForm', () => { it('should do nothing when clicking outcome for readonly form', () => { let formModel = new FormModel(); const outcomeName = 'Custom Action'; - let outcome = new FormOutcomeModel(formModel, {id: 'custom1', name: outcomeName}); + let outcome = new FormOutcomeModel(formModel, { id: 'custom1', name: outcomeName }); formComponent.form = formModel; spyOn(formComponent, 'completeTaskForm').and.stub(); @@ -398,7 +399,7 @@ describe('ActivitiForm', () => { it('should require loaded form when clicking outcome', () => { let formModel = new FormModel(); const outcomeName = 'Custom Action'; - let outcome = new FormOutcomeModel(formModel, {id: 'custom1', name: outcomeName}); + let outcome = new FormOutcomeModel(formModel, { id: 'custom1', name: outcomeName }); formComponent.readOnly = false; formComponent.form = null; @@ -407,7 +408,7 @@ describe('ActivitiForm', () => { it('should not execute unknown system outcome', () => { let formModel = new FormModel(); - let outcome = new FormOutcomeModel(formModel, {id: 'unknown', name: 'Unknown', isSystem: true}); + let outcome = new FormOutcomeModel(formModel, { id: 'unknown', name: 'Unknown', isSystem: true }); formComponent.form = formModel; expect(formComponent.onOutcomeClicked(outcome)).toBeFalsy(); @@ -415,12 +416,12 @@ describe('ActivitiForm', () => { it('should require custom action name to complete form', () => { let formModel = new FormModel(); - let outcome = new FormOutcomeModel(formModel, {id: 'custom'}); + let outcome = new FormOutcomeModel(formModel, { id: 'custom' }); formComponent.form = formModel; expect(formComponent.onOutcomeClicked(outcome)).toBeFalsy(); - outcome = new FormOutcomeModel(formModel, {id: 'custom', name: 'Custom'}); + outcome = new FormOutcomeModel(formModel, { id: 'custom', name: 'Custom' }); spyOn(formComponent, 'completeTaskForm').and.stub(); expect(formComponent.onOutcomeClicked(outcome)).toBeTruthy(); }); @@ -429,7 +430,7 @@ describe('ActivitiForm', () => { spyOn(formService, 'getTask').and.returnValue(Observable.of({})); spyOn(formService, 'getTaskForm').and.callFake((taskId) => { return Observable.create(observer => { - observer.next({taskId: taskId}); + observer.next({ taskId: taskId }); observer.complete(); }); }); @@ -465,7 +466,7 @@ describe('ActivitiForm', () => { spyOn(formService, 'getTask').and.returnValue(Observable.of({})); spyOn(formService, 'getTaskForm').and.callFake((taskId) => { return Observable.create(observer => { - observer.next({taskId: taskId}); + observer.next({ taskId: taskId }); observer.complete(); }); }); @@ -481,7 +482,7 @@ describe('ActivitiForm', () => { it('should fetch and parse form definition by id', () => { spyOn(formService, 'getFormDefinitionById').and.callFake((formId) => { return Observable.create(observer => { - observer.next({id: formId}); + observer.next({ id: formId }); observer.complete(); }); }); @@ -520,7 +521,7 @@ describe('ActivitiForm', () => { spyOn(formService, 'getFormDefinitionById').and.callFake((formName) => { return Observable.create(observer => { - observer.next({name: formName}); + observer.next({ name: formName }); observer.complete(); }); }); @@ -556,8 +557,8 @@ describe('ActivitiForm', () => { let formModel = new FormModel({ taskId: '123', fields: [ - {id: 'field1'}, - {id: 'field2'} + { id: 'field1' }, + { id: 'field2' } ] }); formComponent.form = formModel; @@ -573,7 +574,7 @@ describe('ActivitiForm', () => { spyOn(formService, 'saveTaskForm').and.callFake(() => Observable.throw(error)); spyOn(formComponent, 'handleError').and.stub(); - formComponent.form = new FormModel({taskId: '123'}); + formComponent.form = new FormModel({ taskId: '123' }); formComponent.saveTaskForm(); expect(formComponent.handleError).toHaveBeenCalledWith(error); @@ -618,8 +619,8 @@ describe('ActivitiForm', () => { let formModel = new FormModel({ taskId: '123', fields: [ - {id: 'field1'}, - {id: 'field2'} + { id: 'field1' }, + { id: 'field2' } ] }); @@ -638,7 +639,7 @@ describe('ActivitiForm', () => { let form = formComponent.parseForm({ id: '', fields: [ - {id: 'field1', type: FormFieldTypes.CONTAINER} + { id: 'field1', type: FormFieldTypes.CONTAINER } ] }); @@ -651,7 +652,7 @@ describe('ActivitiForm', () => { it('should provide outcomes for form definition', () => { spyOn(formComponent, 'getFormDefinitionOutcomes').and.callThrough(); - let form = formComponent.parseForm({id: ''}); + let form = formComponent.parseForm({ id: '' }); expect(formComponent.getFormDefinitionOutcomes).toHaveBeenCalledWith(form); }); @@ -724,7 +725,7 @@ describe('ActivitiForm', () => { let metadata = {}; spyOn(nodeService, 'getNodeMetadata').and.returnValue( Observable.create(observer => { - observer.next({metadata: metadata}); + observer.next({ metadata: metadata }); observer.complete(); }) ); @@ -814,4 +815,30 @@ describe('ActivitiForm', () => { formComponent.onOutcomeClicked(outcome); }); + it('should refresh form values when data is changed', () => { + formComponent.form = new FormModel(fakeForm); + let formFields = formComponent.form.getFormFields(); + + let labelField = formFields.find(field => field.id === 'label'); + let radioField = formFields.find(field => field.id === 'raduio'); + expect(labelField.value).toBe('empty'); + expect(radioField.value).toBeNull(); + + let formValues: any = {}; + formValues.label = { + id: 'option_1', + name: 'test1' + }; + formValues.raduio = { id: 'option_1', name: 'Option 1' }; + let change = new SimpleChange(null, formValues, false); + formComponent.data = formValues; + formComponent.ngOnChanges({ 'data': change }); + + formFields = formComponent.form.getFormFields(); + labelField = formFields.find(field => field.id === 'label'); + radioField = formFields.find(field => field.id === 'raduio'); + expect(labelField.value).toBe('option_1'); + expect(radioField.value).toBe('option_1'); + }); + }); diff --git a/ng2-components/ng2-activiti-form/src/components/activiti-form.component.ts b/ng2-components/ng2-activiti-form/src/components/activiti-form.component.ts index c7293759bc..e150640dab 100644 --- a/ng2-components/ng2-activiti-form/src/components/activiti-form.component.ts +++ b/ng2-components/ng2-activiti-form/src/components/activiti-form.component.ts @@ -100,6 +100,9 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges { @Output() formLoaded: EventEmitter = new EventEmitter(); + @Output() + formDataRefreshed: EventEmitter = new EventEmitter(); + @Output() executeOutcome: EventEmitter = new EventEmitter(); @@ -202,6 +205,12 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges { this.loadFormForEcmNode(); return; } + + let data = changes['data']; + if (data && data.currentValue) { + this.refreshFormData(); + return; + } } /** @@ -424,6 +433,12 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges { } } + private refreshFormData() { + this.form = new FormModel(this.form.json, this.data, this.readOnly, this.formService); + this.onFormLoaded(this.form); + this.onFormDataRefreshed(this.form); + } + private loadFormForEcmNode(): void { this.nodeService.getNodeMetadata(this.nodeId).subscribe(data => { this.data = data.metadata; @@ -471,6 +486,11 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges { this.formService.formLoaded.next(new FormEvent(form)); } + protected onFormDataRefreshed(form: FormModel) { + this.formDataRefreshed.emit(form); + this.formService.formDataRefreshed.next(new FormEvent(form)); + } + protected onTaskSaved(form: FormModel) { this.formSaved.emit(form); this.formService.taskSaved.next(new FormEvent(form)); 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 6af8d97b08..bdb0b57009 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 @@ -109,7 +109,7 @@ export class FormModel { } if (json.fields) { let saveOutcome = new FormOutcomeModel(this, { id: FormModel.SAVE_OUTCOME, name: 'Save', isSystem: true }); - let completeOutcome = new FormOutcomeModel(this, {id: FormModel.COMPLETE_OUTCOME, name: 'Complete', isSystem: true }); + let completeOutcome = new FormOutcomeModel(this, { id: FormModel.COMPLETE_OUTCOME, name: 'Complete', isSystem: true }); let startProcessOutcome = new FormOutcomeModel(this, { id: FormModel.START_PROCESS_OUTCOME, name: 'Start Process', isSystem: true }); let customOutcomes = (json.outcomes || []).map(obj => new FormOutcomeModel(this, obj)); @@ -137,7 +137,7 @@ export class FormModel { let field = this.fields[i]; if (field instanceof ContainerModel) { - let container = field; + let container = field; result.push(container.field); result.push(...container.field.fields); } @@ -203,7 +203,11 @@ export class FormModel { for (let field of this.getFormFields()) { if (data[field.id]) { field.json.value = data[field.id]; - field.value = data[field.id]; + field.value = field.parseValue(field.json); + if (field.type === FormFieldTypes.DROPDOWN || + field.type === FormFieldTypes.RADIO_BUTTONS) { + field.value = data[field.id].id; + } } } } 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 ae1c700629..61ff29f94e 100644 --- a/ng2-components/ng2-activiti-form/src/services/form.service.ts +++ b/ng2-components/ng2-activiti-form/src/services/form.service.ts @@ -33,6 +33,7 @@ export class FormService { static GENERIC_ERROR_MESSAGE: string = 'Server error'; formLoaded: Subject = new Subject(); + formDataRefreshed: Subject = new Subject(); formFieldValueChanged: Subject = new Subject(); formEvents: Subject = new Subject(); taskCompleted: Subject = new Subject();