mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[ADF-584] [ADF-3561] Validation error summary for error component (#3795)
* emit Forms error * add demo * add documentation remove old form tag deprecated in 1.x fix translation outcome * remove prevent default validation * fix lint
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
.form-container {
|
||||
padding: 10px;
|
||||
}
|
@@ -1,6 +1,19 @@
|
||||
<div class="form-container">
|
||||
<adf-form
|
||||
[showRefreshButton]="false"
|
||||
[form]="form">
|
||||
</adf-form>
|
||||
<div class="main-content">
|
||||
<h1>Form Component</h1>
|
||||
|
||||
<div class="form-container">
|
||||
<adf-form
|
||||
[showRefreshButton]="false"
|
||||
[form]="form"
|
||||
(formError)="logErrors($event)">
|
||||
</adf-form>
|
||||
</div>
|
||||
|
||||
<div class="console" #console>
|
||||
<h3>Error log:</h3>
|
||||
<p *ngFor="let error of errorFields">Error {{ error.name }} {{error.validationSummary.message | translate}}</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
32
demo-shell/src/app/components/form/form.component.scss
Normal file
32
demo-shell/src/app/components/form/form.component.scss
Normal file
@@ -0,0 +1,32 @@
|
||||
.form-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.card-view {
|
||||
width: 30%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.console {
|
||||
width: 60%;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-left: 10px;
|
||||
height: 500px;
|
||||
overflow: scroll;
|
||||
padding-bottom: 30px;
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
display: block;
|
||||
font-family: monospace, monospace;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
@@ -15,45 +15,38 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @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, Inject, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { FormModel, FormService, FormOutcomeEvent } from '@alfresco/adf-core';
|
||||
import { Component, Inject, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { FormModel, FormFieldModel, FormService, FormOutcomeEvent } from '@alfresco/adf-core';
|
||||
import { InMemoryFormService } from '../../services/in-memory-form.service';
|
||||
import { DemoForm } from './demo-form';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-form',
|
||||
templateUrl: 'form.component.html',
|
||||
styleUrls: ['form.component.css'],
|
||||
styleUrls: ['form.component.scss'],
|
||||
providers: [
|
||||
{ provide: FormService, useClass: InMemoryFormService }
|
||||
],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class FormComponent implements OnInit {
|
||||
export class FormComponent implements OnInit, OnDestroy {
|
||||
|
||||
form: FormModel;
|
||||
errorFields: FormFieldModel[] = [];
|
||||
private subscriptions: Subscription[] = [];
|
||||
|
||||
constructor(@Inject(FormService) private formService: InMemoryFormService) {
|
||||
formService.executeOutcome.subscribe((formOutcomeEvent: FormOutcomeEvent) => {
|
||||
formOutcomeEvent.preventDefault();
|
||||
});
|
||||
|
||||
this.subscriptions.push(
|
||||
formService.executeOutcome.subscribe((formOutcomeEvent: FormOutcomeEvent) => {
|
||||
formOutcomeEvent.preventDefault();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
logErrors(errorFields: FormFieldModel[]) {
|
||||
this.errorFields = errorFields;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -61,4 +54,9 @@ export class FormComponent implements OnInit {
|
||||
this.form = this.formService.parseForm(formDefinitionJSON);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subscriptions.forEach(subscription => subscription.unsubscribe());
|
||||
this.subscriptions = [];
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -29,7 +29,11 @@ import {
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { ProcessInstanceFilterRepresentation, Pagination, UserProcessInstanceFilterRepresentation } from 'alfresco-js-api';
|
||||
import {
|
||||
ProcessInstanceFilterRepresentation,
|
||||
Pagination,
|
||||
UserProcessInstanceFilterRepresentation
|
||||
} from 'alfresco-js-api';
|
||||
import {
|
||||
FORM_FIELD_VALIDATORS, FormEvent, FormFieldEvent, FormRenderingService, FormService,
|
||||
DynamicTableRow, ValidateDynamicTableRowEvent, AppConfigService, PaginationComponent, UserPreferenceValues
|
||||
@@ -53,7 +57,7 @@ import {
|
||||
TaskListComponent
|
||||
} from '@alfresco/adf-process-services';
|
||||
import { LogService } from '@alfresco/adf-core';
|
||||
import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { AlfrescoApiService, UserPreferencesService, ValidateFormEvent } from '@alfresco/adf-core';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component';
|
||||
import { DemoFieldValidator } from './demo-field-validator';
|
||||
@@ -198,6 +202,10 @@ export class ProcessServiceComponent implements AfterViewInit, OnDestroy, OnInit
|
||||
|
||||
formService.formContentClicked.subscribe(content => {
|
||||
this.showContentPreview(content);
|
||||
}),
|
||||
|
||||
formService.validateForm.subscribe((validateFormEvent: ValidateFormEvent) => {
|
||||
this.logService.log('Error form:' + validateFormEvent.errorsField);
|
||||
})
|
||||
);
|
||||
|
||||
@@ -257,7 +265,7 @@ export class ProcessServiceComponent implements AfterViewInit, OnDestroy, OnInit
|
||||
this.showTaskTab = event.index === this.tabs.tasks;
|
||||
this.relocateLocationToTask();
|
||||
} else if (index === PROCESS_ROUTE) {
|
||||
this.showProcessTab = event.index === this.tabs.processes;
|
||||
this.showProcessTab = event.index === this.tabs.processes;
|
||||
this.relocateLocationToProcess();
|
||||
} else if (index === REPORT_ROUTE) {
|
||||
this.relocateLocationToReport();
|
||||
|
@@ -80,6 +80,7 @@ Any content in the body of `<adf-form>` will be shown when no form definition is
|
||||
| formCompleted | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormModel`](../../lib/core/form/components/widgets/core/form.model.ts)`>` | Emitted when the form is submitted with the `Complete` outcome. |
|
||||
| formContentClicked | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ContentLinkModel`](../../lib/core/form/components/widgets/core/content-link.model.ts)`>` | Emitted when form content is clicked. |
|
||||
| formDataRefreshed | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormModel`](../../lib/core/form/components/widgets/core/form.model.ts)`>` | Emitted when form values are refreshed due to a data property change. |
|
||||
| formError | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormFieldModel`](../core/form-field.model.md)`[]>` | Emitted when form validations has validation error. |
|
||||
| formLoaded | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormModel`](../../lib/core/form/components/widgets/core/form.model.ts)`>` | Emitted when the form is loaded or reloaded. |
|
||||
| formSaved | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormModel`](../../lib/core/form/components/widgets/core/form.model.ts)`>` | Emitted when the form is submitted with the `Save` or custom outcomes. |
|
||||
| onError | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when any error occurs. |
|
||||
|
@@ -57,6 +57,7 @@ Displays the Start [`Form`](../../lib/process-services/task-list/models/form.mod
|
||||
| formCompleted | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormModel`](../../lib/core/form/components/widgets/core/form.model.ts)`>` | Emitted when the form is submitted with the `Complete` outcome. |
|
||||
| formContentClicked | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`ContentLinkModel`](../../lib/core/form/components/widgets/core/content-link.model.ts)`>` | Emitted when a field of the form is clicked. |
|
||||
| formDataRefreshed | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormModel`](../../lib/core/form/components/widgets/core/form.model.ts)`>` | Emitted when form values are refreshed due to a data property change. |
|
||||
| formError | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormFieldModel`](../core/form-field.model.md)`[]>` | Emitted when form validations has validation error. |
|
||||
| formLoaded | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormModel`](../../lib/core/form/components/widgets/core/form.model.ts)`>` | Emitted when the form is loaded or reloaded. |
|
||||
| formSaved | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<`[`FormModel`](../../lib/core/form/components/widgets/core/form.model.ts)`>` | Emitted when the form is submitted with the `Save` or custom outcomes. |
|
||||
| onError | [`EventEmitter`](https://angular.io/api/core/EventEmitter)`<any>` | Emitted when any error occurs. |
|
||||
|
@@ -1,79 +0,0 @@
|
||||
/*!
|
||||
* @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 AlfrescoApi = require('alfresco-js-api-node');
|
||||
import TestConfig = require('../test.config');
|
||||
|
||||
import fs = require('fs');
|
||||
import path = require('path');
|
||||
|
||||
let buildNumber = process.env.TRAVIS_BUILD_NUMBER;
|
||||
let saveScreenshot = process.env.SAVE_SCREENSHOT;
|
||||
|
||||
describe('Save screenshot at the end', () => {
|
||||
|
||||
beforeAll(async (done) => {
|
||||
|
||||
if (saveScreenshot === 'true') {
|
||||
if (!buildNumber) {
|
||||
buildNumber = Date.now();
|
||||
}
|
||||
|
||||
let alfrescoJsApi = new AlfrescoApi({
|
||||
provider: 'ECM',
|
||||
hostEcm: TestConfig.adf.url
|
||||
});
|
||||
|
||||
let files = fs.readdirSync(path.join(__dirname, '../../e2e-output/screenshots'));
|
||||
|
||||
if (files && files.length > 0) {
|
||||
alfrescoJsApi.login(TestConfig.adf.adminEmail, TestConfig.adf.adminPassword);
|
||||
|
||||
let folder = await alfrescoJsApi.nodes.addNode('-my-', {
|
||||
'name': 'insights',
|
||||
'relativePath': 'Build-screenshot/Screenshot-e2e-' + buildNumber,
|
||||
'nodeType': 'cm:folder'
|
||||
}, {}, {
|
||||
'overwrite': true
|
||||
});
|
||||
|
||||
for (const fileName of files) {
|
||||
|
||||
let pathFile = path.join(__dirname, '../../e2e-output/screenshots', fileName);
|
||||
let file: any = fs.createReadStream(pathFile);
|
||||
|
||||
await alfrescoJsApi.upload.uploadFile(
|
||||
file,
|
||||
'',
|
||||
folder.entry.id,
|
||||
null,
|
||||
{
|
||||
'name': file.name,
|
||||
'nodeType': 'cm:content'
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('screenshot need it', () => {
|
||||
expect(true).toEqual(true);
|
||||
});
|
||||
});
|
@@ -38,7 +38,7 @@ import { WidgetComponent } from './../widgets/widget.component';
|
||||
declare var adf: any;
|
||||
|
||||
@Component({
|
||||
selector: 'adf-form-field, form-field',
|
||||
selector: 'adf-form-field',
|
||||
template: `
|
||||
<div [id]="'field-'+field?.id+'-container'"
|
||||
[hidden]="!field?.isVisible"
|
||||
|
@@ -31,7 +31,7 @@
|
||||
|
||||
<div *ngIf="!form.hasTabs() && form.hasFields()">
|
||||
<div *ngFor="let field of form.fields">
|
||||
<form-field [field]="field.field"></form-field>
|
||||
<adf-form-field [field]="field.field"></adf-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
@@ -43,7 +43,7 @@
|
||||
[disabled]="!isOutcomeButtonEnabled(outcome)"
|
||||
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
|
||||
(click)="onOutcomeClicked(outcome)">
|
||||
{{outcome.name | uppercase}}
|
||||
{{outcome.name | uppercase | translate}}
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
|
@@ -16,16 +16,24 @@
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||
import {
|
||||
Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit,
|
||||
Output, SimpleChanges, ViewEncapsulation
|
||||
} from '@angular/core';
|
||||
import { FormErrorEvent, FormEvent } from './../events/index';
|
||||
import { EcmModelService } from './../services/ecm-model.service';
|
||||
import { FormService } from './../services/form.service';
|
||||
import { NodeService } from './../services/node.service';
|
||||
import { ContentLinkModel } from './widgets/core/content-link.model';
|
||||
import { FormFieldModel, FormModel, FormOutcomeEvent, FormOutcomeModel, FormValues, FormFieldValidator } from './widgets/core/index';
|
||||
import {
|
||||
FormFieldModel, FormModel, FormOutcomeEvent, FormOutcomeModel,
|
||||
FormValues, FormFieldValidator
|
||||
} from './widgets/core/index';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { ValidateFormEvent } from './../events/validate-form.event';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-form',
|
||||
@@ -33,14 +41,14 @@ import { switchMap } from 'rxjs/operators';
|
||||
styleUrls: ['./form.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class FormComponent implements OnInit, OnChanges {
|
||||
export class FormComponent implements OnInit, OnChanges, OnDestroy {
|
||||
|
||||
static SAVE_OUTCOME_ID: string = '$save';
|
||||
static COMPLETE_OUTCOME_ID: string = '$complete';
|
||||
static START_PROCESS_OUTCOME_ID: string = '$startProcess';
|
||||
static CUSTOM_OUTCOME_ID: string = '$custom';
|
||||
static COMPLETE_BUTTON_COLOR: string = 'primary';
|
||||
static COMPLETE_OUTCOME_NAME: string ='Complete'
|
||||
static COMPLETE_OUTCOME_NAME: string = 'Complete'
|
||||
|
||||
/** Underlying form model instance. */
|
||||
@Input()
|
||||
@@ -138,18 +146,25 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
@Output()
|
||||
formDataRefreshed: EventEmitter<FormModel> = new EventEmitter<FormModel>();
|
||||
|
||||
/** Emitted when form validations has validation error.*/
|
||||
@Output()
|
||||
formError: EventEmitter<FormFieldModel[]> = new EventEmitter<FormFieldModel[]>();
|
||||
|
||||
/** Emitted when any outcome is executed. Default behaviour can be prevented
|
||||
* via `event.preventDefault()`.
|
||||
*/
|
||||
@Output()
|
||||
executeOutcome: EventEmitter<FormOutcomeEvent> = new EventEmitter<FormOutcomeEvent>();
|
||||
|
||||
/** @deprecated in 2.4.0, will be renamed in error in 3.x.x */
|
||||
/** Emitted when any error occurs. */
|
||||
@Output()
|
||||
onError: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
debugMode: boolean = false;
|
||||
|
||||
protected subscriptions: Subscription[] = [];
|
||||
|
||||
constructor(protected formService: FormService,
|
||||
protected visibilityService: WidgetVisibilityService,
|
||||
private ecmModelService: EcmModelService,
|
||||
@@ -214,9 +229,21 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.formService.formContentClicked.subscribe((content: ContentLinkModel) => {
|
||||
this.formContentClicked.emit(content);
|
||||
});
|
||||
this.subscriptions.push(
|
||||
this.formService.formContentClicked.subscribe((content: ContentLinkModel) => {
|
||||
this.formContentClicked.emit(content);
|
||||
}),
|
||||
this.formService.validateForm.subscribe((validateFormEvent: ValidateFormEvent) => {
|
||||
if (validateFormEvent.errorsField.length > 0) {
|
||||
this.formError.next(validateFormEvent.errorsField);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subscriptions.forEach(subscription => subscription.unsubscribe());
|
||||
this.subscriptions = [];
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
@@ -338,12 +365,12 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
|
||||
getFormByTaskId(taskId: string): Promise<FormModel> {
|
||||
return new Promise<FormModel>((resolve, reject) => {
|
||||
this.findProcessVariablesByTaskId(taskId).subscribe( (processVariables) => {
|
||||
this.findProcessVariablesByTaskId(taskId).subscribe((processVariables) => {
|
||||
this.formService
|
||||
.getTaskForm(taskId)
|
||||
.subscribe(
|
||||
form => {
|
||||
const parsedForm = this.parseForm(form);
|
||||
const parsedForm = this.parseForm(form);
|
||||
this.visibilityService.refreshVisibility(parsedForm);
|
||||
parsedForm.validateForm();
|
||||
this.form = parsedForm;
|
||||
@@ -364,16 +391,16 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
this.formService
|
||||
.getFormDefinitionById(formId)
|
||||
.subscribe(
|
||||
form => {
|
||||
this.formName = form.name;
|
||||
this.form = this.parseForm(form);
|
||||
this.visibilityService.refreshVisibility(this.form);
|
||||
this.form.validateForm();
|
||||
this.onFormLoaded(this.form);
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
form => {
|
||||
this.formName = form.name;
|
||||
this.form = this.parseForm(form);
|
||||
this.visibilityService.refreshVisibility(this.form);
|
||||
this.form.validateForm();
|
||||
this.onFormLoaded(this.form);
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -381,22 +408,22 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
this.formService
|
||||
.getFormDefinitionByName(formName)
|
||||
.subscribe(
|
||||
id => {
|
||||
this.formService.getFormDefinitionById(id).subscribe(
|
||||
form => {
|
||||
this.form = this.parseForm(form);
|
||||
this.visibilityService.refreshVisibility(this.form);
|
||||
this.form.validateForm();
|
||||
this.onFormLoaded(this.form);
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
);
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
id => {
|
||||
this.formService.getFormDefinitionById(id).subscribe(
|
||||
form => {
|
||||
this.form = this.parseForm(form);
|
||||
this.visibilityService.refreshVisibility(this.form);
|
||||
this.form.validateForm();
|
||||
this.onFormLoaded(this.form);
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
);
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -405,11 +432,11 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
this.formService
|
||||
.saveTaskForm(this.form.taskId, this.form.values)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.onTaskSaved(this.form);
|
||||
this.storeFormAsMetadata();
|
||||
},
|
||||
error => this.onTaskSavedError(this.form, error)
|
||||
() => {
|
||||
this.onTaskSaved(this.form);
|
||||
this.storeFormAsMetadata();
|
||||
},
|
||||
error => this.onTaskSavedError(this.form, error)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -419,11 +446,11 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
this.formService
|
||||
.completeTaskForm(this.form.taskId, this.form.values, outcome)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.onTaskCompleted(this.form);
|
||||
this.storeFormAsMetadata();
|
||||
},
|
||||
error => this.onTaskCompletedError(this.form, error)
|
||||
() => {
|
||||
this.onTaskCompleted(this.form);
|
||||
this.storeFormAsMetadata();
|
||||
},
|
||||
error => this.onTaskCompletedError(this.form, error)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -470,9 +497,9 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
|
||||
private loadFormForEcmNode(nodeId: string): void {
|
||||
this.nodeService.getNodeMetadata(nodeId).subscribe(data => {
|
||||
this.data = data.metadata;
|
||||
this.loadFormFromActiviti(data.nodeType);
|
||||
},
|
||||
this.data = data.metadata;
|
||||
this.loadFormFromActiviti(data.nodeType);
|
||||
},
|
||||
this.handleError);
|
||||
}
|
||||
|
||||
@@ -501,8 +528,8 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
private storeFormAsMetadata() {
|
||||
if (this.saveMetadata) {
|
||||
this.ecmModelService.createEcmTypeForActivitiForm(this.formName, this.form).subscribe(type => {
|
||||
this.nodeService.createNodeMetadata(type.nodeType || type.entry.prefixedName, EcmModelService.MODEL_NAMESPACE, this.form.values, this.path, this.nameNode);
|
||||
},
|
||||
this.nodeService.createNodeMetadata(type.nodeType || type.entry.prefixedName, EcmModelService.MODEL_NAMESPACE, this.form.values, this.path, this.nameNode);
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
|
@@ -12,12 +12,13 @@
|
||||
|
||||
<div *ngIf="!form.hasTabs() && form.hasFields()">
|
||||
<div *ngFor="let field of form.fields">
|
||||
<form-field [field]="field.field"></form-field>
|
||||
<adf-form-field [field]="field.field"></adf-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
<mat-card-content class="adf-start-form-actions" *ngIf="showOutcomeButtons && form.hasOutcomes()" #outcomesContainer>
|
||||
<ng-content select="[form-custom-button]"></ng-content>
|
||||
<mat-card-content class="adf-start-form-actions" *ngIf="showOutcomeButtons && form.hasOutcomes()"
|
||||
#outcomesContainer>
|
||||
<ng-content select="[form-custom-button]"></ng-content>
|
||||
<button *ngFor="let outcome of form.outcomes"
|
||||
mat-button
|
||||
[attr.data-automation-id]="'adf-form-' + outcome.name | lowercase"
|
||||
@@ -25,7 +26,7 @@
|
||||
[class.mdl-button--colored]="!outcome.isSystem"
|
||||
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
|
||||
(click)="onOutcomeClicked(outcome)">
|
||||
{{outcome.name}}
|
||||
{{outcome.name| uppercase | translate}}
|
||||
</button>
|
||||
</mat-card-content>
|
||||
<mat-card-actions *ngIf="showRefreshButton">
|
||||
|
@@ -15,30 +15,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild, ViewEncapsulation, OnDestroy } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnChanges,
|
||||
OnInit,
|
||||
Output,
|
||||
SimpleChanges,
|
||||
ViewChild,
|
||||
ViewEncapsulation,
|
||||
OnDestroy
|
||||
} from '@angular/core';
|
||||
import { FormService } from './../services/form.service';
|
||||
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
||||
import { FormComponent } from './form.component';
|
||||
import { ContentLinkModel } from './widgets/core/content-link.model';
|
||||
import { FormOutcomeModel } from './widgets/core/index';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { ValidateFormEvent } from './../events/validate-form.event';
|
||||
|
||||
/**
|
||||
* Displays the start form for a named process definition, which can be used to retrieve values to start a new process.
|
||||
*
|
||||
* After the form has been completed the form values are available from the attribute component.form.values and
|
||||
* component.form.isValid (boolean) can be used to check the if the form is valid or not. Both of these properties are
|
||||
* updated as the user types into the form.
|
||||
*
|
||||
* @Input
|
||||
* {processDefinitionId} string: The process definition ID
|
||||
* {showOutcomeButtons} boolean: Whether form outcome buttons should be shown, this is now always active to show form outcomes
|
||||
* @Output
|
||||
* {formLoaded} EventEmitter - This event is fired when the form is loaded, it pass all the value in the form.
|
||||
* {formSaved} EventEmitter - This event is fired when the form is saved, it pass all the value in the form.
|
||||
* {formCompleted} EventEmitter - This event is fired when the form is completed, it pass all the value in the form.
|
||||
*
|
||||
*/
|
||||
@Component({
|
||||
selector: 'adf-start-form',
|
||||
templateUrl: './start-form.component.html',
|
||||
@@ -47,8 +43,6 @@ import { Subscription } from 'rxjs';
|
||||
})
|
||||
export class StartFormComponent extends FormComponent implements OnChanges, OnInit, OnDestroy {
|
||||
|
||||
private subscriptions: Subscription[] = [];
|
||||
|
||||
/** Definition ID of the process to start. */
|
||||
@Input()
|
||||
processDefinitionId: string;
|
||||
@@ -90,6 +84,11 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
|
||||
this.subscriptions.push(
|
||||
this.formService.formContentClicked.subscribe(content => {
|
||||
this.formContentClicked.emit(content);
|
||||
}),
|
||||
this.formService.validateForm.subscribe((validateFormEvent: ValidateFormEvent) => {
|
||||
if (validateFormEvent.errorsField.length > 0) {
|
||||
this.formError.next(validateFormEvent.errorsField);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -155,8 +154,8 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
|
||||
|
||||
/** @override */
|
||||
isOutcomeButtonVisible(outcome: FormOutcomeModel, isFormReadOnly: boolean): boolean {
|
||||
if (outcome && outcome.isSystem && ( outcome.name === FormOutcomeModel.SAVE_ACTION ||
|
||||
outcome.name === FormOutcomeModel.COMPLETE_ACTION )) {
|
||||
if (outcome && outcome.isSystem && (outcome.name === FormOutcomeModel.SAVE_ACTION ||
|
||||
outcome.name === FormOutcomeModel.COMPLETE_ACTION)) {
|
||||
return false;
|
||||
} else if (outcome && outcome.name === FormOutcomeModel.START_PROCESS_ACTION) {
|
||||
return true;
|
||||
|
@@ -13,7 +13,7 @@
|
||||
|
||||
<section class="grid-list" *ngIf="content?.isExpanded">
|
||||
<div class="grid-list-item" *ngFor="let field of fields" [style.width]="getColumnWith(field)">
|
||||
<form-field *ngIf="field" [field]="field"></form-field>
|
||||
<adf-form-field *ngIf="field" [field]="field"></adf-form-field>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
@@ -271,27 +271,6 @@ describe('FormModel', () => {
|
||||
form.validateField(field);
|
||||
});
|
||||
|
||||
it('should skip form validation when default behaviour prevented', () => {
|
||||
const form = new FormModel({}, null, false, formService);
|
||||
|
||||
let prevented = false;
|
||||
|
||||
formService.validateForm.subscribe((event: ValidateFormEvent) => {
|
||||
event.isValid = false;
|
||||
event.preventDefault();
|
||||
prevented = true;
|
||||
});
|
||||
|
||||
const field = jasmine.createSpyObj('FormFieldModel', ['validate']);
|
||||
spyOn(form, 'getFormFields').and.returnValue([field]);
|
||||
|
||||
form.validateForm();
|
||||
|
||||
expect(prevented).toBeTruthy();
|
||||
expect(form.isValid).toBeFalsy();
|
||||
expect(field.validate).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should skip field validation when default behaviour prevented', () => {
|
||||
const form = new FormModel({}, null, false, formService);
|
||||
|
||||
|
@@ -15,9 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import { FormFieldEvent, ValidateFormEvent, ValidateFormFieldEvent } from './../../../events/index';
|
||||
import { FormFieldEvent } from './../../../events/form-field.event';
|
||||
import { ValidateFormFieldEvent } from './../../../events/validate-form-field.event';
|
||||
import { ValidateFormEvent } from './../../../events/validate-form.event';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { ContainerModel } from './container.model';
|
||||
import { FormFieldTemplates } from './form-field-templates';
|
||||
@@ -120,9 +122,21 @@ 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 startProcessOutcome = new FormOutcomeModel(this, { id: FormModel.START_PROCESS_OUTCOME, name: 'Start Process', isSystem: true });
|
||||
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 startProcessOutcome = new FormOutcomeModel(this, {
|
||||
id: FormModel.START_PROCESS_OUTCOME,
|
||||
name: 'Start Process',
|
||||
isSystem: true
|
||||
});
|
||||
|
||||
let customOutcomes = (json.outcomes || []).map(obj => new FormOutcomeModel(this, obj));
|
||||
|
||||
@@ -176,27 +190,27 @@ export class FormModel {
|
||||
* @memberof FormModel
|
||||
*/
|
||||
validateForm(): void {
|
||||
const validateFormEvent = new ValidateFormEvent(this);
|
||||
const validateFormEvent: any = new ValidateFormEvent(this);
|
||||
|
||||
let errorsField: FormFieldModel[] = [];
|
||||
|
||||
let fields = this.getFormFields();
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
if (!fields[i].validate()) {
|
||||
errorsField.push(fields[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (errorsField.length > 0) {
|
||||
this._isValid = false;
|
||||
}
|
||||
|
||||
if (this.formService) {
|
||||
validateFormEvent.isValid = this._isValid;
|
||||
validateFormEvent.errorsField = errorsField;
|
||||
this.formService.validateForm.next(validateFormEvent);
|
||||
}
|
||||
|
||||
this._isValid = validateFormEvent.isValid;
|
||||
|
||||
if (validateFormEvent.defaultPrevented) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (validateFormEvent.isValid) {
|
||||
let fields = this.getFormFields();
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
if (!fields[i].validate()) {
|
||||
this._isValid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,8 +241,8 @@ export class FormModel {
|
||||
|
||||
if (!field.validate()) {
|
||||
this._isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.validateForm();
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<mat-tab-group>
|
||||
<mat-tab *ngFor="let tab of visibleTabs" [label]="tab.title">
|
||||
<div *ngFor="let field of tab.fields">
|
||||
<form-field [field]="field.field"></form-field>
|
||||
<adf-form-field [field]="field.field"></adf-form-field>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
|
@@ -17,10 +17,12 @@
|
||||
|
||||
import { FormModel } from './../components/widgets/core/index';
|
||||
import { FormEvent } from './form.event';
|
||||
import { FormFieldModel } from '../components/widgets/core/form-field.model';
|
||||
|
||||
export class ValidateFormEvent extends FormEvent {
|
||||
|
||||
isValid = true;
|
||||
errorsField: FormFieldModel[] = [];
|
||||
|
||||
constructor(form: FormModel) {
|
||||
super(form);
|
||||
|
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"SAVE": "SAVE",
|
||||
"START": "COMPLETE",
|
||||
"START PROCESS": "START PROCESS",
|
||||
"FORM": {
|
||||
"START_FORM": {
|
||||
"TITLE": "Start Form"
|
||||
|
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"SAVE": "SALVA",
|
||||
"COMPLETE": "COMPLETA",
|
||||
"START PROCESS": "INIZIA PROCESSO",
|
||||
"FORM": {
|
||||
"START_FORM": {
|
||||
"TITLE": "Modulo di inizio"
|
||||
|
Reference in New Issue
Block a user