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="main-content">
|
||||||
|
<h1>Form Component</h1>
|
||||||
|
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<adf-form
|
<adf-form
|
||||||
[showRefreshButton]="false"
|
[showRefreshButton]="false"
|
||||||
[form]="form">
|
[form]="form"
|
||||||
|
(formError)="logErrors($event)">
|
||||||
</adf-form>
|
</adf-form>
|
||||||
</div>
|
</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.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
import { Component, Inject, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';
|
||||||
* @license
|
import { FormModel, FormFieldModel, FormService, FormOutcomeEvent } from '@alfresco/adf-core';
|
||||||
* 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 { InMemoryFormService } from '../../services/in-memory-form.service';
|
import { InMemoryFormService } from '../../services/in-memory-form.service';
|
||||||
import { DemoForm } from './demo-form';
|
import { DemoForm } from './demo-form';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-form',
|
selector: 'app-form',
|
||||||
templateUrl: 'form.component.html',
|
templateUrl: 'form.component.html',
|
||||||
styleUrls: ['form.component.css'],
|
styleUrls: ['form.component.scss'],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: FormService, useClass: InMemoryFormService }
|
{ provide: FormService, useClass: InMemoryFormService }
|
||||||
],
|
],
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class FormComponent implements OnInit {
|
export class FormComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
form: FormModel;
|
form: FormModel;
|
||||||
|
errorFields: FormFieldModel[] = [];
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
constructor(@Inject(FormService) private formService: InMemoryFormService) {
|
constructor(@Inject(FormService) private formService: InMemoryFormService) {
|
||||||
|
|
||||||
|
this.subscriptions.push(
|
||||||
formService.executeOutcome.subscribe((formOutcomeEvent: FormOutcomeEvent) => {
|
formService.executeOutcome.subscribe((formOutcomeEvent: FormOutcomeEvent) => {
|
||||||
formOutcomeEvent.preventDefault();
|
formOutcomeEvent.preventDefault();
|
||||||
});
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
logErrors(errorFields: FormFieldModel[]) {
|
||||||
|
this.errorFields = errorFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -61,4 +54,9 @@ export class FormComponent implements OnInit {
|
|||||||
this.form = this.formService.parseForm(formDefinitionJSON);
|
this.form = this.formService.parseForm(formDefinitionJSON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.subscriptions.forEach(subscription => subscription.unsubscribe());
|
||||||
|
this.subscriptions = [];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,11 @@ import {
|
|||||||
Output
|
Output
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ProcessInstanceFilterRepresentation, Pagination, UserProcessInstanceFilterRepresentation } from 'alfresco-js-api';
|
import {
|
||||||
|
ProcessInstanceFilterRepresentation,
|
||||||
|
Pagination,
|
||||||
|
UserProcessInstanceFilterRepresentation
|
||||||
|
} from 'alfresco-js-api';
|
||||||
import {
|
import {
|
||||||
FORM_FIELD_VALIDATORS, FormEvent, FormFieldEvent, FormRenderingService, FormService,
|
FORM_FIELD_VALIDATORS, FormEvent, FormFieldEvent, FormRenderingService, FormService,
|
||||||
DynamicTableRow, ValidateDynamicTableRowEvent, AppConfigService, PaginationComponent, UserPreferenceValues
|
DynamicTableRow, ValidateDynamicTableRowEvent, AppConfigService, PaginationComponent, UserPreferenceValues
|
||||||
@@ -53,7 +57,7 @@ import {
|
|||||||
TaskListComponent
|
TaskListComponent
|
||||||
} from '@alfresco/adf-process-services';
|
} from '@alfresco/adf-process-services';
|
||||||
import { LogService } from '@alfresco/adf-core';
|
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 { Subscription } from 'rxjs';
|
||||||
import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component';
|
import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component';
|
||||||
import { DemoFieldValidator } from './demo-field-validator';
|
import { DemoFieldValidator } from './demo-field-validator';
|
||||||
@@ -198,6 +202,10 @@ export class ProcessServiceComponent implements AfterViewInit, OnDestroy, OnInit
|
|||||||
|
|
||||||
formService.formContentClicked.subscribe(content => {
|
formService.formContentClicked.subscribe(content => {
|
||||||
this.showContentPreview(content);
|
this.showContentPreview(content);
|
||||||
|
}),
|
||||||
|
|
||||||
|
formService.validateForm.subscribe((validateFormEvent: ValidateFormEvent) => {
|
||||||
|
this.logService.log('Error form:' + validateFormEvent.errorsField);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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;
|
declare var adf: any;
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-form-field, form-field',
|
selector: 'adf-form-field',
|
||||||
template: `
|
template: `
|
||||||
<div [id]="'field-'+field?.id+'-container'"
|
<div [id]="'field-'+field?.id+'-container'"
|
||||||
[hidden]="!field?.isVisible"
|
[hidden]="!field?.isVisible"
|
||||||
|
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
<div *ngIf="!form.hasTabs() && form.hasFields()">
|
<div *ngIf="!form.hasTabs() && form.hasFields()">
|
||||||
<div *ngFor="let field of form.fields">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
[disabled]="!isOutcomeButtonEnabled(outcome)"
|
[disabled]="!isOutcomeButtonEnabled(outcome)"
|
||||||
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
|
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
|
||||||
(click)="onOutcomeClicked(outcome)">
|
(click)="onOutcomeClicked(outcome)">
|
||||||
{{outcome.name | uppercase}}
|
{{outcome.name | uppercase | translate}}
|
||||||
</button>
|
</button>
|
||||||
</mat-card-actions>
|
</mat-card-actions>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
@@ -16,16 +16,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* tslint:disable */
|
/* 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 { FormErrorEvent, FormEvent } from './../events/index';
|
||||||
import { EcmModelService } from './../services/ecm-model.service';
|
import { EcmModelService } from './../services/ecm-model.service';
|
||||||
import { FormService } from './../services/form.service';
|
import { FormService } from './../services/form.service';
|
||||||
import { NodeService } from './../services/node.service';
|
import { NodeService } from './../services/node.service';
|
||||||
import { ContentLinkModel } from './widgets/core/content-link.model';
|
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 { Observable, of } from 'rxjs';
|
||||||
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
||||||
import { switchMap } from 'rxjs/operators';
|
import { switchMap } from 'rxjs/operators';
|
||||||
|
import { ValidateFormEvent } from './../events/validate-form.event';
|
||||||
|
import { Subscription } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'adf-form',
|
selector: 'adf-form',
|
||||||
@@ -33,7 +41,7 @@ import { switchMap } from 'rxjs/operators';
|
|||||||
styleUrls: ['./form.component.scss'],
|
styleUrls: ['./form.component.scss'],
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class FormComponent implements OnInit, OnChanges {
|
export class FormComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
|
|
||||||
static SAVE_OUTCOME_ID: string = '$save';
|
static SAVE_OUTCOME_ID: string = '$save';
|
||||||
static COMPLETE_OUTCOME_ID: string = '$complete';
|
static COMPLETE_OUTCOME_ID: string = '$complete';
|
||||||
@@ -138,18 +146,25 @@ export class FormComponent implements OnInit, OnChanges {
|
|||||||
@Output()
|
@Output()
|
||||||
formDataRefreshed: EventEmitter<FormModel> = new EventEmitter<FormModel>();
|
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
|
/** Emitted when any outcome is executed. Default behaviour can be prevented
|
||||||
* via `event.preventDefault()`.
|
* via `event.preventDefault()`.
|
||||||
*/
|
*/
|
||||||
@Output()
|
@Output()
|
||||||
executeOutcome: EventEmitter<FormOutcomeEvent> = new EventEmitter<FormOutcomeEvent>();
|
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. */
|
/** Emitted when any error occurs. */
|
||||||
@Output()
|
@Output()
|
||||||
onError: EventEmitter<any> = new EventEmitter<any>();
|
onError: EventEmitter<any> = new EventEmitter<any>();
|
||||||
|
|
||||||
debugMode: boolean = false;
|
debugMode: boolean = false;
|
||||||
|
|
||||||
|
protected subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
constructor(protected formService: FormService,
|
constructor(protected formService: FormService,
|
||||||
protected visibilityService: WidgetVisibilityService,
|
protected visibilityService: WidgetVisibilityService,
|
||||||
private ecmModelService: EcmModelService,
|
private ecmModelService: EcmModelService,
|
||||||
@@ -214,9 +229,21 @@ export class FormComponent implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.subscriptions.push(
|
||||||
this.formService.formContentClicked.subscribe((content: ContentLinkModel) => {
|
this.formService.formContentClicked.subscribe((content: ContentLinkModel) => {
|
||||||
this.formContentClicked.emit(content);
|
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) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
@@ -12,11 +12,12 @@
|
|||||||
|
|
||||||
<div *ngIf="!form.hasTabs() && form.hasFields()">
|
<div *ngIf="!form.hasTabs() && form.hasFields()">
|
||||||
<div *ngFor="let field of form.fields">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<mat-card-content class="adf-start-form-actions" *ngIf="showOutcomeButtons && form.hasOutcomes()" #outcomesContainer>
|
<mat-card-content class="adf-start-form-actions" *ngIf="showOutcomeButtons && form.hasOutcomes()"
|
||||||
|
#outcomesContainer>
|
||||||
<ng-content select="[form-custom-button]"></ng-content>
|
<ng-content select="[form-custom-button]"></ng-content>
|
||||||
<button *ngFor="let outcome of form.outcomes"
|
<button *ngFor="let outcome of form.outcomes"
|
||||||
mat-button
|
mat-button
|
||||||
@@ -25,7 +26,7 @@
|
|||||||
[class.mdl-button--colored]="!outcome.isSystem"
|
[class.mdl-button--colored]="!outcome.isSystem"
|
||||||
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
|
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
|
||||||
(click)="onOutcomeClicked(outcome)">
|
(click)="onOutcomeClicked(outcome)">
|
||||||
{{outcome.name}}
|
{{outcome.name| uppercase | translate}}
|
||||||
</button>
|
</button>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
<mat-card-actions *ngIf="showRefreshButton">
|
<mat-card-actions *ngIf="showRefreshButton">
|
||||||
|
@@ -15,30 +15,26 @@
|
|||||||
* limitations under the License.
|
* 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 { FormService } from './../services/form.service';
|
||||||
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
||||||
import { FormComponent } from './form.component';
|
import { FormComponent } from './form.component';
|
||||||
import { ContentLinkModel } from './widgets/core/content-link.model';
|
import { ContentLinkModel } from './widgets/core/content-link.model';
|
||||||
import { FormOutcomeModel } from './widgets/core/index';
|
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({
|
@Component({
|
||||||
selector: 'adf-start-form',
|
selector: 'adf-start-form',
|
||||||
templateUrl: './start-form.component.html',
|
templateUrl: './start-form.component.html',
|
||||||
@@ -47,8 +43,6 @@ import { Subscription } from 'rxjs';
|
|||||||
})
|
})
|
||||||
export class StartFormComponent extends FormComponent implements OnChanges, OnInit, OnDestroy {
|
export class StartFormComponent extends FormComponent implements OnChanges, OnInit, OnDestroy {
|
||||||
|
|
||||||
private subscriptions: Subscription[] = [];
|
|
||||||
|
|
||||||
/** Definition ID of the process to start. */
|
/** Definition ID of the process to start. */
|
||||||
@Input()
|
@Input()
|
||||||
processDefinitionId: string;
|
processDefinitionId: string;
|
||||||
@@ -90,6 +84,11 @@ export class StartFormComponent extends FormComponent implements OnChanges, OnIn
|
|||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
this.formService.formContentClicked.subscribe(content => {
|
this.formService.formContentClicked.subscribe(content => {
|
||||||
this.formContentClicked.emit(content);
|
this.formContentClicked.emit(content);
|
||||||
|
}),
|
||||||
|
this.formService.validateForm.subscribe((validateFormEvent: ValidateFormEvent) => {
|
||||||
|
if (validateFormEvent.errorsField.length > 0) {
|
||||||
|
this.formError.next(validateFormEvent.errorsField);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<section class="grid-list" *ngIf="content?.isExpanded">
|
<section class="grid-list" *ngIf="content?.isExpanded">
|
||||||
<div class="grid-list-item" *ngFor="let field of fields" [style.width]="getColumnWith(field)">
|
<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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@@ -271,27 +271,6 @@ describe('FormModel', () => {
|
|||||||
form.validateField(field);
|
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', () => {
|
it('should skip field validation when default behaviour prevented', () => {
|
||||||
const form = new FormModel({}, null, false, formService);
|
const form = new FormModel({}, null, false, formService);
|
||||||
|
|
||||||
|
@@ -17,7 +17,9 @@
|
|||||||
|
|
||||||
/* 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 { FormService } from './../../../services/form.service';
|
||||||
import { ContainerModel } from './container.model';
|
import { ContainerModel } from './container.model';
|
||||||
import { FormFieldTemplates } from './form-field-templates';
|
import { FormFieldTemplates } from './form-field-templates';
|
||||||
@@ -120,9 +122,21 @@ export class FormModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (json.fields) {
|
if (json.fields) {
|
||||||
let saveOutcome = new FormOutcomeModel(this, { id: FormModel.SAVE_OUTCOME, name: 'Save', isSystem: true });
|
let saveOutcome = new FormOutcomeModel(this, {
|
||||||
let completeOutcome = new FormOutcomeModel(this, { id: FormModel.COMPLETE_OUTCOME, name: 'Complete', isSystem: true });
|
id: FormModel.SAVE_OUTCOME,
|
||||||
let startProcessOutcome = new FormOutcomeModel(this, { id: FormModel.START_PROCESS_OUTCOME, name: 'Start Process', isSystem: true });
|
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));
|
let customOutcomes = (json.outcomes || []).map(obj => new FormOutcomeModel(this, obj));
|
||||||
|
|
||||||
@@ -176,27 +190,27 @@ export class FormModel {
|
|||||||
* @memberof FormModel
|
* @memberof FormModel
|
||||||
*/
|
*/
|
||||||
validateForm(): void {
|
validateForm(): void {
|
||||||
const validateFormEvent = new ValidateFormEvent(this);
|
const validateFormEvent: any = new ValidateFormEvent(this);
|
||||||
|
|
||||||
if (this.formService) {
|
let errorsField: FormFieldModel[] = [];
|
||||||
this.formService.validateForm.next(validateFormEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._isValid = validateFormEvent.isValid;
|
|
||||||
|
|
||||||
if (validateFormEvent.defaultPrevented) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validateFormEvent.isValid) {
|
|
||||||
let fields = this.getFormFields();
|
let fields = this.getFormFields();
|
||||||
for (let i = 0; i < fields.length; i++) {
|
for (let i = 0; i < fields.length; i++) {
|
||||||
if (!fields[i].validate()) {
|
if (!fields[i].validate()) {
|
||||||
|
errorsField.push(fields[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorsField.length > 0) {
|
||||||
this._isValid = false;
|
this._isValid = false;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.formService) {
|
||||||
|
validateFormEvent.isValid = this._isValid;
|
||||||
|
validateFormEvent.errorsField = errorsField;
|
||||||
|
this.formService.validateForm.next(validateFormEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -227,8 +241,8 @@ export class FormModel {
|
|||||||
|
|
||||||
if (!field.validate()) {
|
if (!field.validate()) {
|
||||||
this._isValid = false;
|
this._isValid = false;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.validateForm();
|
this.validateForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<mat-tab-group>
|
<mat-tab-group>
|
||||||
<mat-tab *ngFor="let tab of visibleTabs" [label]="tab.title">
|
<mat-tab *ngFor="let tab of visibleTabs" [label]="tab.title">
|
||||||
<div *ngFor="let field of tab.fields">
|
<div *ngFor="let field of tab.fields">
|
||||||
<form-field [field]="field.field"></form-field>
|
<adf-form-field [field]="field.field"></adf-form-field>
|
||||||
</div>
|
</div>
|
||||||
</mat-tab>
|
</mat-tab>
|
||||||
</mat-tab-group>
|
</mat-tab-group>
|
||||||
|
@@ -17,10 +17,12 @@
|
|||||||
|
|
||||||
import { FormModel } from './../components/widgets/core/index';
|
import { FormModel } from './../components/widgets/core/index';
|
||||||
import { FormEvent } from './form.event';
|
import { FormEvent } from './form.event';
|
||||||
|
import { FormFieldModel } from '../components/widgets/core/form-field.model';
|
||||||
|
|
||||||
export class ValidateFormEvent extends FormEvent {
|
export class ValidateFormEvent extends FormEvent {
|
||||||
|
|
||||||
isValid = true;
|
isValid = true;
|
||||||
|
errorsField: FormFieldModel[] = [];
|
||||||
|
|
||||||
constructor(form: FormModel) {
|
constructor(form: FormModel) {
|
||||||
super(form);
|
super(form);
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"SAVE": "SAVE",
|
||||||
|
"START": "COMPLETE",
|
||||||
|
"START PROCESS": "START PROCESS",
|
||||||
"FORM": {
|
"FORM": {
|
||||||
"START_FORM": {
|
"START_FORM": {
|
||||||
"TITLE": "Start Form"
|
"TITLE": "Start Form"
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"SAVE": "SALVA",
|
||||||
|
"COMPLETE": "COMPLETA",
|
||||||
|
"START PROCESS": "INIZIA PROCESSO",
|
||||||
"FORM": {
|
"FORM": {
|
||||||
"START_FORM": {
|
"START_FORM": {
|
||||||
"TITLE": "Modulo di inizio"
|
"TITLE": "Modulo di inizio"
|
||||||
|
Reference in New Issue
Block a user