diff --git a/ng2-components/ng2-activiti-form/README.md b/ng2-components/ng2-activiti-form/README.md index 5f025df8a4..e766b05e0b 100644 --- a/ng2-components/ng2-activiti-form/README.md +++ b/ng2-components/ng2-activiti-form/README.md @@ -106,8 +106,9 @@ The recommended set of properties can be found in the following table: | 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()` | -All `form*` events recieve an instance of the `FormModel` as event argument for ease of development: +All `form*` events receive an instance of the `FormModel` as event argument for ease of development: **MyView.component.html** ```html @@ -124,6 +125,56 @@ onFormSaved(form: FormModel) { } ``` +#### Controlling outcome execution behaviour + +If absolutely needed it is possible taking full control over form outcome execution by means of `executeOutcome` event. +This event is fired upon each outcome execution, both system and custom ones. + +You can prevent default behaviour by calling `event.preventDefault()`. +This allows for example having custom form validation scenarios and/or additional validation summary presentation. + +Alternatively you may want just running additional code on outcome execution without suppressing default one. + +**MyView.component.html** +```html + + +``` + +**MyView.component.ts** +```ts +import { FormOutcomeEvent } from 'ng2-activiti-form'; + +export class MyView { + + validateForm(event: FormOutcomeEvent) { + let outcome = event.outcome; + + // you can also get additional properties of outcomes + // if you defined them within outcome definition + + if (outcome) { + let form = outcome.form; + if (form) { + // check/update the form here + event.preventDefault(); + } + } + } + +} +``` + +There are two additional functions that can be of a great value when controlling outcomes: + +- `saveTaskForm()` - saves current form +- `completeTaskForm(outcome?: string)` - save and complete form with a given outcome name + +**Please note that if `event.preventDefault()` is not called then default outcome behaviour +will also be executed after your custom code.** + ## Build from sources Alternatively you can build component from sources with the following commands: 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 a55bb0445a..8a2a2911cf 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 @@ -19,7 +19,7 @@ import { it, describe, expect } from '@angular/core/testing'; import { Observable } from 'rxjs/Rx'; import { SimpleChange } from '@angular/core'; import { ActivitiForm } from './activiti-form.component'; -import { FormModel, FormOutcomeModel, FormFieldModel } from './widgets/index'; +import { FormModel, FormOutcomeModel, FormFieldModel, FormOutcomeEvent } from './widgets/index'; import { FormService } from './../services/form.service'; import { WidgetVisibilityService } from './../services/widget-visibility.service'; import { ContainerWidget } from './widgets/container/container.widget'; @@ -582,4 +582,56 @@ describe('ActivitiForm', () => { expect(formComponent.checkVisibility).toHaveBeenCalledWith(fakeField); }); + it('should prevent default outcome execution', () => { + + let outcome = new FormOutcomeModel(new FormModel(), { + id: ActivitiForm.CUSTOM_OUTCOME_ID, + name: 'Custom' + }); + + formComponent.form = new FormModel(); + formComponent.executeOutcome.subscribe((event: FormOutcomeEvent) => { + expect(event.outcome).toBe(outcome); + event.preventDefault(); + expect(event.defaultPrevented).toBeTruthy(); + }); + + let result = formComponent.onOutcomeClicked(outcome); + expect(result).toBeFalsy(); + }); + + it('should not prevent default outcome execution', () => { + let outcome = new FormOutcomeModel(new FormModel(), { + id: ActivitiForm.CUSTOM_OUTCOME_ID, + name: 'Custom' + }); + + formComponent.form = new FormModel(); + formComponent.executeOutcome.subscribe((event: FormOutcomeEvent) => { + expect(event.outcome).toBe(outcome); + expect(event.defaultPrevented).toBeFalsy(); + }); + + spyOn(formComponent, 'completeTaskForm').and.callThrough(); + + let result = formComponent.onOutcomeClicked(outcome); + expect(result).toBeTruthy(); + + expect(formComponent.completeTaskForm).toHaveBeenCalledWith(outcome.name); + }); + + it('should check visibility only if field with form provided', () => { + + formComponent.checkVisibility(null); + expect(visibilityService.updateVisibilityForForm).not.toHaveBeenCalled(); + + let field = new FormFieldModel(null); + formComponent.checkVisibility(field); + expect(visibilityService.updateVisibilityForForm).not.toHaveBeenCalled(); + + field = new FormFieldModel(new FormModel()); + formComponent.checkVisibility(field); + expect(visibilityService.updateVisibilityForForm).toHaveBeenCalledWith(field.form); + }); + }); 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 57bf834072..69865b8a1c 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 @@ -26,7 +26,7 @@ import { import { MATERIAL_DESIGN_DIRECTIVES } from 'ng2-alfresco-core'; import { FormService } from './../services/form.service'; -import { FormModel, FormOutcomeModel, FormValues, FormFieldModel } from './widgets/core/index'; +import { FormModel, FormOutcomeModel, FormValues, FormFieldModel, FormOutcomeEvent } from './widgets/core/index'; import { TabsWidget } from './widgets/tabs/tabs.widget'; import { ContainerWidget } from './widgets/container/container.widget'; @@ -116,6 +116,9 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges { @Output() formLoaded: EventEmitter = new EventEmitter(); + @Output() + executeOutcome: EventEmitter = new EventEmitter(); + form: FormModel; debugMode: boolean = false; @@ -185,6 +188,13 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges { */ onOutcomeClicked(outcome: FormOutcomeModel): boolean { if (!this.readOnly && outcome && this.form) { + + let args = new FormOutcomeEvent(outcome); + this.executeOutcome.emit(args); + if (args.defaultPrevented) { + return false; + } + if (outcome.isSystem) { if (outcome.id === ActivitiForm.SAVE_OUTCOME_ID) { this.saveTaskForm(); @@ -340,6 +350,8 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges { } checkVisibility(field: FormFieldModel) { - this.visibilityService.updateVisibilityForForm(field.form); + if (field && field.form) { + this.visibilityService.updateVisibilityForForm(field.form); + } } } diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-outcome-event.model.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-outcome-event.model.ts new file mode 100644 index 0000000000..abb290c072 --- /dev/null +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-outcome-event.model.ts @@ -0,0 +1,41 @@ +/*! + * @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 { FormOutcomeModel } from './form-outcome.model'; + +export class FormOutcomeEvent { + + private _outcome: FormOutcomeModel; + private _defaultPrevented: boolean = false; + + get outcome(): FormOutcomeModel { + return this._outcome; + } + + get defaultPrevented() { + return this._defaultPrevented; + } + + constructor(outcome: FormOutcomeModel) { + this._outcome = outcome; + } + + preventDefault() { + this._defaultPrevented = true; + } + +} 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 ce68bdba24..7a28d27c75 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 @@ -26,3 +26,4 @@ export * from './container-column.model'; export * from './container.model'; export * from './tab.model'; export * from './form-outcome.model'; +export * from './form-outcome-event.model';