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 0379e071e0..36521d3c6b 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 @@ -4,8 +4,9 @@
-
-

{{form.taskName}}

+
+ {{ form.isValid ? 'event_available' : 'event_busy' }} +

{{form.taskName}}

@@ -19,9 +20,9 @@
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 37204d11d6..3f3497c3ae 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 @@ -98,13 +98,13 @@ describe('ActivitiForm', () => { }); it('should not enable outcome button when model missing', () => { - expect(formComponent.isOutcomeButtonEnabled(null)).toBeFalsy(); + expect(formComponent.isOutcomeButtonVisible(null)).toBeFalsy(); }); it('should enable custom outcome buttons', () => { let formModel = new FormModel(); let outcome = new FormOutcomeModel(formModel, { id: 'action1', name: 'Action 1' }); - expect(formComponent.isOutcomeButtonEnabled(outcome)).toBeTruthy(); + expect(formComponent.isOutcomeButtonVisible(outcome)).toBeTruthy(); }); @@ -113,10 +113,10 @@ describe('ActivitiForm', () => { let outcome = new FormOutcomeModel(formModel, { id: '$save', name: FormOutcomeModel.SAVE_ACTION }); formComponent.showSaveButton = true; - expect(formComponent.isOutcomeButtonEnabled(outcome)).toBeTruthy(); + expect(formComponent.isOutcomeButtonVisible(outcome)).toBeTruthy(); formComponent.showSaveButton = false; - expect(formComponent.isOutcomeButtonEnabled(outcome)).toBeFalsy(); + expect(formComponent.isOutcomeButtonVisible(outcome)).toBeFalsy(); }); it('should allow controlling [save] button visibility', () => { @@ -124,10 +124,10 @@ describe('ActivitiForm', () => { let outcome = new FormOutcomeModel(formModel, { id: '$save', name: FormOutcomeModel.COMPLETE_ACTION }); formComponent.showCompleteButton = true; - expect(formComponent.isOutcomeButtonEnabled(outcome)).toBeTruthy(); + expect(formComponent.isOutcomeButtonVisible(outcome)).toBeTruthy(); formComponent.showCompleteButton = false; - expect(formComponent.isOutcomeButtonEnabled(outcome)).toBeFalsy(); + expect(formComponent.isOutcomeButtonVisible(outcome)).toBeFalsy(); }); it('should load form on refresh', () => { 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 d8d4c61755..721bd0a45b 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 @@ -128,7 +128,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges { showSaveButton: boolean = true; @Input() - showDebugButton: boolean = false; + showDebugButton: boolean = true; @Input() readOnly: boolean = false; @@ -175,6 +175,21 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges { } isOutcomeButtonEnabled(outcome: FormOutcomeModel): boolean { + if (this.form.readOnly) { + return false; + } + + if (outcome) { + // Make 'Save' button always available + if (outcome.name === FormOutcomeModel.SAVE_ACTION) { + return true; + } + return this.form.isValid; + } + return false; + } + + isOutcomeButtonVisible(outcome: FormOutcomeModel): boolean { if (outcome && outcome.name) { if (outcome.name === FormOutcomeModel.COMPLETE_ACTION) { return this.showCompleteButton; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field.model.ts b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field.model.ts index 365a669dcc..44b0eccad8 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field.model.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field.model.ts @@ -65,6 +65,17 @@ export class FormFieldModel extends FormWidgetModel { return this._readOnly; } + isValid(): boolean { + + if (this.required) { + if (this.type === FormFieldTypes.TEXT || this.type === FormFieldTypes.MULTILINE_TEXT) { + return this._value ? true : false; + } + } + + return true; + } + constructor(form: FormModel, json?: any) { super(form, json); @@ -129,7 +140,6 @@ export class FormFieldModel extends FormWidgetModel { } updateForm() { - switch (this.type) { case FormFieldTypes.DROPDOWN: /* @@ -177,5 +187,7 @@ export class FormFieldModel extends FormWidgetModel { this.form.values[this.id] = this.value; } } + + this.form.onFormFieldChanged(this); } } 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 00f72226f5..4bd7946aba 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 @@ -20,6 +20,7 @@ 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'; export class FormModel { @@ -31,6 +32,7 @@ export class FormModel { private _name: string; private _taskId: string; private _taskName: string = FormModel.UNSET_TASK_NAME; + private _isValid: boolean = true; get id(): string { return this._id; @@ -48,6 +50,10 @@ export class FormModel { return this._taskName; } + get isValid(): boolean { + return this._isValid; + } + readOnly: boolean = false; tabs: TabModel[] = []; fields: ContainerModel[] = []; @@ -102,7 +108,8 @@ export class FormModel { if (field.tab) { let tab = tabCache[field.tab]; if (tab) { - tab.fields.push(new ContainerModel(this, field.json)); + // tab.fields.push(new ContainerModel(this, field.json)); + tab.fields.push(field); } } } @@ -119,6 +126,48 @@ export class FormModel { } } + onFormFieldChanged(field: FormFieldModel) { + this.validateField(field); + } + + // TODO: evaluate and cache once the form is loaded + private 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); + } + } + } + + return result; + } + + private validateForm() { + this._isValid = true; + let fields = this.getFormFields(); + for (let i = 0; i < fields.length; i++) { + if (!fields[i].isValid()) { + this._isValid = false; + return; + } + } + } + + private validateField(field: FormFieldModel) { + if (!field) return; + if (!field.isValid()) { + this._isValid = false; + return; + } + this.validateForm(); + } + private parseContainerFields(json: any): ContainerModel[] { let fields = []; diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/multiline-text/multiline-text.widget.html b/ng2-components/ng2-activiti-form/src/components/widgets/multiline-text/multiline-text.widget.html index 2511b63434..a79dd93ef9 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/multiline-text/multiline-text.widget.html +++ b/ng2-components/ng2-activiti-form/src/components/widgets/multiline-text/multiline-text.widget.html @@ -3,6 +3,7 @@ type="text" rows= "3" [attr.id]="field.id" + [attr.required]="isRequired()" [(ngModel)]="field.value" (ngModelChange)="checkVisibility(field)" [disabled]="field.readOnly"> diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/text/text.widget.html b/ng2-components/ng2-activiti-form/src/components/widgets/text/text.widget.html index d74aac765a..67e0a654ce 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/text/text.widget.html +++ b/ng2-components/ng2-activiti-form/src/components/widgets/text/text.widget.html @@ -2,6 +2,7 @@ diff --git a/ng2-components/ng2-activiti-form/src/components/widgets/widget.component.ts b/ng2-components/ng2-activiti-form/src/components/widgets/widget.component.ts index b27efe1214..6bdaa17faa 100644 --- a/ng2-components/ng2-activiti-form/src/components/widgets/widget.component.ts +++ b/ng2-components/ng2-activiti-form/src/components/widgets/widget.component.ts @@ -36,6 +36,13 @@ export class WidgetComponent implements AfterViewInit { return this.field ? true : false; } + isRequired(): any { + if (this.field && this.field.required) { + return true; + } + return null; + } + ngAfterViewInit() { this.setupMaterialComponents(); this.fieldChanged.emit(this.field);