#589 ability to prevent default outcome behaviour

- ability to prevent default outcome behaviour (i.e. custom validation)
- new ‘executeOutcome’ event for DocumentList
- unit tests
- readme updates
This commit is contained in:
Denys Vuika 2016-08-22 14:18:03 +01:00
parent a977e52e8d
commit acfa8ac819
5 changed files with 161 additions and 4 deletions

View File

@ -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
<activiti-form
[taskId]="selectedTask?.id"
executeOutcome="validateForm($event)">
</activiti-form>
```
**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:

View File

@ -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);
});
});

View File

@ -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<FormModel> = new EventEmitter<FormModel>();
@Output()
executeOutcome: EventEmitter<FormOutcomeEvent> = new EventEmitter<FormOutcomeEvent>();
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) {
if (field && field.form) {
this.visibilityService.updateVisibilityForForm(field.form);
}
}
}

View File

@ -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;
}
}

View File

@ -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';