mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-05-19 17:14:57 +00:00
[ADF-1312] form validation enhancements (#2180)
* validation api enhancements - changing 'required' causes re-validation of the form - get field by id * allow binding field validators from html * demo validator * documentation updates * fix after rebase * markdown fixes * markdown linter settings for workspace config (vs code) * restore material theme
This commit is contained in:
parent
6c1a758561
commit
3d65b49af7
12
.vscode/settings.json
vendored
12
.vscode/settings.json
vendored
@ -9,5 +9,15 @@
|
|||||||
"**/.happypack": true
|
"**/.happypack": true
|
||||||
},
|
},
|
||||||
"editor.renderIndentGuides": true,
|
"editor.renderIndentGuides": true,
|
||||||
"tslint.configFile": "ng2-components/tslint.json"
|
"tslint.configFile": "ng2-components/tslint.json",
|
||||||
|
"markdownlint.config": {
|
||||||
|
"MD032": false,
|
||||||
|
"MD004": false,
|
||||||
|
"MD024": false,
|
||||||
|
"MD009": false,
|
||||||
|
"MD013": false,
|
||||||
|
"MD036": false,
|
||||||
|
"MD033" : false,
|
||||||
|
"MD031" : false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,7 @@
|
|||||||
<activiti-task-details #activitidetails
|
<activiti-task-details #activitidetails
|
||||||
[debugMode]="true"
|
[debugMode]="true"
|
||||||
[taskId]="currentTaskId"
|
[taskId]="currentTaskId"
|
||||||
|
[fieldValidators]="fieldValidators"
|
||||||
(formCompleted)="onFormCompleted($event)"
|
(formCompleted)="onFormCompleted($event)"
|
||||||
(formContentClicked)="onFormContentClick($event)"
|
(formContentClicked)="onFormContentClick($event)"
|
||||||
(taskCreated)="onTaskCreated($event)"
|
(taskCreated)="onTaskCreated($event)"
|
||||||
|
@ -15,10 +15,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// tslint:disable-next-line:adf-file-name
|
||||||
import { AfterViewInit, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
import { AfterViewInit, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { AnalyticsReportListComponent } from 'ng2-activiti-analytics';
|
import { AnalyticsReportListComponent } from 'ng2-activiti-analytics';
|
||||||
import { FormEvent, FormFieldEvent, FormRenderingService, FormService } from 'ng2-activiti-form';
|
import { FORM_FIELD_VALIDATORS, FormEvent, FormFieldEvent, FormRenderingService, FormService } from 'ng2-activiti-form';
|
||||||
import {
|
import {
|
||||||
FilterProcessRepresentationModel,
|
FilterProcessRepresentationModel,
|
||||||
ProcessFiltersComponent,
|
ProcessFiltersComponent,
|
||||||
@ -43,6 +44,7 @@ import {
|
|||||||
} from 'ng2-alfresco-datatable';
|
} from 'ng2-alfresco-datatable';
|
||||||
import { Subscription } from 'rxjs/Rx';
|
import { Subscription } from 'rxjs/Rx';
|
||||||
import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component';
|
import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component';
|
||||||
|
import { DemoFieldValidator } from './demo-field-validator';
|
||||||
|
|
||||||
declare var componentHandler;
|
declare var componentHandler;
|
||||||
|
|
||||||
@ -109,6 +111,11 @@ export class ActivitiDemoComponent implements AfterViewInit, OnDestroy, OnInit {
|
|||||||
dataTasks: ObjectDataTableAdapter;
|
dataTasks: ObjectDataTableAdapter;
|
||||||
dataProcesses: ObjectDataTableAdapter;
|
dataProcesses: ObjectDataTableAdapter;
|
||||||
|
|
||||||
|
fieldValidators = [
|
||||||
|
...FORM_FIELD_VALIDATORS,
|
||||||
|
new DemoFieldValidator()
|
||||||
|
];
|
||||||
|
|
||||||
constructor(private elementRef: ElementRef,
|
constructor(private elementRef: ElementRef,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@ -141,11 +148,13 @@ export class ActivitiDemoComponent implements AfterViewInit, OnDestroy, OnInit {
|
|||||||
console.log(`Field value changed. Form: ${e.form.id}, Field: ${e.field.id}, Value: ${e.field.value}`);
|
console.log(`Field value changed. Form: ${e.form.id}, Field: ${e.field.id}, Value: ${e.field.value}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Uncomment this block to see form event handling in action
|
||||||
|
/*
|
||||||
formService.formEvents.subscribe((event: Event) => {
|
formService.formEvents.subscribe((event: Event) => {
|
||||||
console.log('Event fired:' + event.type);
|
console.log('Event fired:' + event.type);
|
||||||
console.log('Event Target:' + event.target);
|
console.log('Event Target:' + event.target);
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { FormFieldModel, FormFieldTypes, FormFieldValidator } from 'ng2-activiti-form';
|
||||||
|
|
||||||
|
export class DemoFieldValidator implements FormFieldValidator {
|
||||||
|
|
||||||
|
isSupported(field: FormFieldModel): boolean {
|
||||||
|
return field && field.type === FormFieldTypes.TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(field: FormFieldModel): boolean {
|
||||||
|
if (this.isSupported(field)) {
|
||||||
|
if (field.value && field.value.toLowerCase() === 'admin') {
|
||||||
|
field.validationSummary = 'Sorry, the value cannot be "admin".';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -188,6 +188,117 @@ If needed, you can completely redefine the set of validators used by the form.
|
|||||||
|
|
||||||
All changes to `fieldValidators` collection are automatically applied to all the further validation cycles.
|
All changes to `fieldValidators` collection are automatically applied to all the further validation cycles.
|
||||||
|
|
||||||
|
##### Custom set of validators
|
||||||
|
|
||||||
|
You can provide your own set of field validators based on either custom validator instances, or a mixture of default and custom ones.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<adf-form [fieldValidators]="fieldValidators"></adf-form>
|
||||||
|
```
|
||||||
|
|
||||||
|
The Form component exposes a special `FORM_FIELD_VALIDATORS` constant that allows you get a quick access to all system validator instances.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { FORM_FIELD_VALIDATORS } from 'ng2-activiti-form';
|
||||||
|
|
||||||
|
@Component({...})
|
||||||
|
export class AppComponent {
|
||||||
|
|
||||||
|
fieldValidators = [
|
||||||
|
// default set of ADF validators if needed
|
||||||
|
...FORM_FIELD_VALIDATORS,
|
||||||
|
|
||||||
|
// custom validators
|
||||||
|
new MyValidator1(),
|
||||||
|
new MyValidator2()
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Custom validator example
|
||||||
|
|
||||||
|
A form field validator must implement the "FormFieldValidator" interface:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export interface FormFieldValidator {
|
||||||
|
|
||||||
|
isSupported(field: FormFieldModel): boolean;
|
||||||
|
validate(field: FormFieldModel): boolean;
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
There might be many different validators used for various field types and purposes,
|
||||||
|
so the validation layer needs every validator instance to support "isSupported" call.
|
||||||
|
|
||||||
|
It is up to validator to declare support for a form field.
|
||||||
|
If you want to check field types the [FormFieldTypes](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field-types.ts) class can help you with the predefined constants and helper methods.
|
||||||
|
|
||||||
|
In addition every validator has access to all underlying APIs of the [FormFieldModel](https://github.com/Alfresco/alfresco-ng2-components/blob/master/ng2-components/ng2-activiti-form/src/components/widgets/core/form-field.model.ts),
|
||||||
|
including the reference to the Form instance and so other form fields.
|
||||||
|
|
||||||
|
Below is a source code for a demo validator that is executed for all the "TEXT" fields, and ensures the value is not "admin", otherwise the `field.validationSummary` value is set to an error.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { FormFieldModel, FormFieldTypes, FormFieldValidator } from 'ng2-activiti-form';
|
||||||
|
|
||||||
|
export class DemoFieldValidator implements FormFieldValidator {
|
||||||
|
|
||||||
|
isSupported(field: FormFieldModel): boolean {
|
||||||
|
return field && field.type === FormFieldTypes.TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
validate(field: FormFieldModel): boolean {
|
||||||
|
if (this.isSupported(field)) {
|
||||||
|
if (field.value && field.value.toLowerCase() === 'admin') {
|
||||||
|
field.validationSummary = 'Sorry, the value cannot be "admin".';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Your component can extend the default validation set instead of replacing it entirely.
|
||||||
|
In the example below we redefine a default validation set with an additional "DemoFieldValidator":
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { DemoFieldValidator } from './demo-field-validator';
|
||||||
|
|
||||||
|
@Component({...})
|
||||||
|
export class AppComponent {
|
||||||
|
|
||||||
|
fieldValidators = [
|
||||||
|
...FORM_FIELD_VALIDATORS,
|
||||||
|
new DemoFieldValidator()
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now use the 'fieldValidators' property with the Form or Task Details components to assign custom validator set for the underlying Form Model:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<activiti-task-details
|
||||||
|
[fieldValidators]="fieldValidators"
|
||||||
|
taskId="123">
|
||||||
|
</<activiti-task-details>
|
||||||
|
|
||||||
|
<!-- OR -->
|
||||||
|
|
||||||
|
<adf-form
|
||||||
|
[fieldValidators]="fieldValidators"
|
||||||
|
taskI="123">
|
||||||
|
</adf-form>
|
||||||
|
```
|
||||||
|
|
||||||
|
Now if you run the application and try to enter "admin" in one of the text fields (either optional or required), you should see the following error:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
### Advanced properties
|
### Advanced properties
|
||||||
|
|
||||||
The following properties are for complex customisation purposes:
|
The following properties are for complex customisation purposes:
|
||||||
|
BIN
ng2-components/ng2-activiti-form/docs/assets/demo-validator.png
Normal file
BIN
ng2-components/ng2-activiti-form/docs/assets/demo-validator.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
@ -47,6 +47,7 @@ export * from './src/services/ecm-model.service';
|
|||||||
export * from './src/services/node.service';
|
export * from './src/services/node.service';
|
||||||
export * from './src/services/form-rendering.service';
|
export * from './src/services/form-rendering.service';
|
||||||
export * from './src/events/index';
|
export * from './src/events/index';
|
||||||
|
export { FORM_FIELD_VALIDATORS } from './src/components/widgets/core/form-field-validator';
|
||||||
|
|
||||||
// Old deprecated import
|
// Old deprecated import
|
||||||
import {FormComponent as ActivitiForm } from './src/components/form.component';
|
import {FormComponent as ActivitiForm } from './src/components/form.component';
|
||||||
|
@ -22,7 +22,7 @@ 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 } from './widgets/core/index';
|
import { FormFieldModel, FormModel, FormOutcomeEvent, FormOutcomeModel, FormValues, FormFieldValidator } from './widgets/core/index';
|
||||||
|
|
||||||
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
||||||
|
|
||||||
@ -90,6 +90,9 @@ export class FormComponent implements OnInit, OnChanges {
|
|||||||
@Input()
|
@Input()
|
||||||
showValidationIcon: boolean = true;
|
showValidationIcon: boolean = true;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
fieldValidators: FormFieldValidator[] = [];
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
formSaved: EventEmitter<FormModel> = new EventEmitter<FormModel>();
|
formSaved: EventEmitter<FormModel> = new EventEmitter<FormModel>();
|
||||||
|
|
||||||
@ -308,7 +311,7 @@ export class FormComponent implements OnInit, OnChanges {
|
|||||||
.getTaskForm(taskId)
|
.getTaskForm(taskId)
|
||||||
.subscribe(
|
.subscribe(
|
||||||
form => {
|
form => {
|
||||||
this.form = new FormModel(form, this.data, this.readOnly, this.formService);
|
this.form = this.parseForm(form);
|
||||||
this.onFormLoaded(this.form);
|
this.onFormLoaded(this.form);
|
||||||
resolve(this.form);
|
resolve(this.form);
|
||||||
},
|
},
|
||||||
@ -396,6 +399,10 @@ export class FormComponent implements OnInit, OnChanges {
|
|||||||
if (!json.fields) {
|
if (!json.fields) {
|
||||||
form.outcomes = this.getFormDefinitionOutcomes(form);
|
form.outcomes = this.getFormDefinitionOutcomes(form);
|
||||||
}
|
}
|
||||||
|
if (this.fieldValidators && this.fieldValidators.length > 0) {
|
||||||
|
console.log('Applying custom field validators');
|
||||||
|
form.fieldValidators = this.fieldValidators;
|
||||||
|
}
|
||||||
return form;
|
return form;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -419,7 +426,7 @@ export class FormComponent implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private refreshFormData() {
|
private refreshFormData() {
|
||||||
this.form = new FormModel(this.form.json, this.data, this.readOnly, this.formService);
|
this.form = this.parseForm(this.form.json);
|
||||||
this.onFormLoaded(this.form);
|
this.onFormLoaded(this.form);
|
||||||
this.onFormDataRefreshed(this.form);
|
this.onFormDataRefreshed(this.form);
|
||||||
}
|
}
|
||||||
|
@ -355,3 +355,16 @@ export class RegExFieldValidator implements FormFieldValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const FORM_FIELD_VALIDATORS = [
|
||||||
|
new RequiredFieldValidator(),
|
||||||
|
new NumberFieldValidator(),
|
||||||
|
new MinLengthFieldValidator(),
|
||||||
|
new MaxLengthFieldValidator(),
|
||||||
|
new MinValueFieldValidator(),
|
||||||
|
new MaxValueFieldValidator(),
|
||||||
|
new RegExFieldValidator(),
|
||||||
|
new DateFieldValidator(),
|
||||||
|
new MinDateFieldValidator(),
|
||||||
|
new MaxDateFieldValidator()
|
||||||
|
];
|
||||||
|
@ -32,6 +32,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
private _value: string;
|
private _value: string;
|
||||||
private _readOnly: boolean = false;
|
private _readOnly: boolean = false;
|
||||||
private _isValid: boolean = true;
|
private _isValid: boolean = true;
|
||||||
|
private _required: boolean = false;
|
||||||
|
|
||||||
readonly defaultDateFormat: string = 'D-M-YYYY';
|
readonly defaultDateFormat: string = 'D-M-YYYY';
|
||||||
|
|
||||||
@ -40,7 +41,6 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
required: boolean;
|
|
||||||
overrideId: boolean;
|
overrideId: boolean;
|
||||||
tab: string;
|
tab: string;
|
||||||
rowspan: number = 1;
|
rowspan: number = 1;
|
||||||
@ -99,6 +99,15 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
this.updateForm();
|
this.updateForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get required(): boolean {
|
||||||
|
return this._required;
|
||||||
|
}
|
||||||
|
|
||||||
|
set required(value: boolean) {
|
||||||
|
this._required = value;
|
||||||
|
this.updateForm();
|
||||||
|
}
|
||||||
|
|
||||||
get isValid(): boolean {
|
get isValid(): boolean {
|
||||||
return this._isValid;
|
return this._isValid;
|
||||||
}
|
}
|
||||||
@ -126,7 +135,7 @@ export class FormFieldModel extends FormWidgetModel {
|
|||||||
this.id = json.id;
|
this.id = json.id;
|
||||||
this.name = json.name;
|
this.name = json.name;
|
||||||
this.type = json.type;
|
this.type = json.type;
|
||||||
this.required = <boolean> json.required;
|
this._required = <boolean> json.required;
|
||||||
this._readOnly = <boolean> json.readOnly || json.type === 'readonly';
|
this._readOnly = <boolean> json.readOnly || json.type === 'readonly';
|
||||||
this.overrideId = <boolean> json.overrideId;
|
this.overrideId = <boolean> json.overrideId;
|
||||||
this.tab = json.tab;
|
this.tab = json.tab;
|
||||||
|
@ -20,6 +20,8 @@ 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 { FormFieldTypes } from './form-field-types';
|
import { FormFieldTypes } from './form-field-types';
|
||||||
|
import { FORM_FIELD_VALIDATORS, FormFieldValidator } from './form-field-validator';
|
||||||
|
import { FormFieldModel } from './form-field.model';
|
||||||
import { FormOutcomeModel } from './form-outcome.model';
|
import { FormOutcomeModel } from './form-outcome.model';
|
||||||
import { FormModel } from './form.model';
|
import { FormModel } from './form.model';
|
||||||
import { TabModel } from './tab.model';
|
import { TabModel } from './tab.model';
|
||||||
@ -381,4 +383,67 @@ describe('FormModel', () => {
|
|||||||
expect(field.validate).not.toHaveBeenCalled();
|
expect(field.validate).not.toHaveBeenCalled();
|
||||||
expect(form.validateForm).not.toHaveBeenCalled();
|
expect(form.validateForm).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should get field by id', () => {
|
||||||
|
const form = new FormModel({}, null, false, formService);
|
||||||
|
const field = { id: 'field1' };
|
||||||
|
spyOn(form, 'getFormFields').and.returnValue([field]);
|
||||||
|
|
||||||
|
const result = form.getFieldById('field1');
|
||||||
|
expect(result).toBe(field);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use custom field validator', () => {
|
||||||
|
const form = new FormModel({}, null, false, formService);
|
||||||
|
const testField = new FormFieldModel(form, {
|
||||||
|
id: 'test-field-1'
|
||||||
|
});
|
||||||
|
|
||||||
|
spyOn(form, 'getFormFields').and.returnValue([testField]);
|
||||||
|
|
||||||
|
let validator = <FormFieldValidator> {
|
||||||
|
isSupported(field: FormFieldModel): boolean {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
validate(field: FormFieldModel): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
spyOn(validator, 'validate').and.callThrough();
|
||||||
|
|
||||||
|
form.fieldValidators = [validator];
|
||||||
|
form.validateForm();
|
||||||
|
|
||||||
|
expect(validator.validate).toHaveBeenCalledWith(testField);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should re-validate the field when required attribute changes', () => {
|
||||||
|
const form = new FormModel({}, null, false, formService);
|
||||||
|
const testField = new FormFieldModel(form, {
|
||||||
|
id: 'test-field-1',
|
||||||
|
required: false
|
||||||
|
});
|
||||||
|
|
||||||
|
spyOn(form, 'getFormFields').and.returnValue([testField]);
|
||||||
|
spyOn(form, 'onFormFieldChanged').and.callThrough();
|
||||||
|
spyOn(form, 'validateField').and.callThrough();
|
||||||
|
|
||||||
|
testField.required = true;
|
||||||
|
|
||||||
|
expect(testField.required).toBeTruthy();
|
||||||
|
expect(form.onFormFieldChanged).toHaveBeenCalledWith(testField);
|
||||||
|
expect(form.validateField).toHaveBeenCalledWith(testField);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not change default validators export', () => {
|
||||||
|
const form = new FormModel({}, null, false, formService);
|
||||||
|
const defaultLength = FORM_FIELD_VALIDATORS.length;
|
||||||
|
|
||||||
|
expect(form.fieldValidators.length).toBe(defaultLength);
|
||||||
|
form.fieldValidators.push(<any> {});
|
||||||
|
|
||||||
|
expect(form.fieldValidators.length).toBe(defaultLength + 1);
|
||||||
|
expect(FORM_FIELD_VALIDATORS.length).toBe(defaultLength);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -29,17 +29,8 @@ import { FormWidgetModel, FormWidgetModelCache } from './form-widget.model';
|
|||||||
import { TabModel } from './tab.model';
|
import { TabModel } from './tab.model';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DateFieldValidator,
|
FORM_FIELD_VALIDATORS,
|
||||||
FormFieldValidator,
|
FormFieldValidator
|
||||||
MaxDateFieldValidator,
|
|
||||||
MaxLengthFieldValidator,
|
|
||||||
MaxValueFieldValidator,
|
|
||||||
MinDateFieldValidator,
|
|
||||||
MinLengthFieldValidator,
|
|
||||||
MinValueFieldValidator,
|
|
||||||
NumberFieldValidator,
|
|
||||||
RegExFieldValidator,
|
|
||||||
RequiredFieldValidator
|
|
||||||
} from './form-field-validator';
|
} from './form-field-validator';
|
||||||
|
|
||||||
export class FormModel {
|
export class FormModel {
|
||||||
@ -67,7 +58,7 @@ export class FormModel {
|
|||||||
fields: FormWidgetModel[] = [];
|
fields: FormWidgetModel[] = [];
|
||||||
outcomes: FormOutcomeModel[] = [];
|
outcomes: FormOutcomeModel[] = [];
|
||||||
customFieldTemplates: FormFieldTemplates = {};
|
customFieldTemplates: FormFieldTemplates = {};
|
||||||
fieldValidators: FormFieldValidator[] = [];
|
fieldValidators: FormFieldValidator[] = [...FORM_FIELD_VALIDATORS];
|
||||||
readonly selectedOutcome: string;
|
readonly selectedOutcome: string;
|
||||||
|
|
||||||
values: FormValues = {};
|
values: FormValues = {};
|
||||||
@ -138,19 +129,6 @@ export class FormModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fieldValidators = [
|
|
||||||
new RequiredFieldValidator(),
|
|
||||||
new NumberFieldValidator(),
|
|
||||||
new MinLengthFieldValidator(),
|
|
||||||
new MaxLengthFieldValidator(),
|
|
||||||
new MinValueFieldValidator(),
|
|
||||||
new MaxValueFieldValidator(),
|
|
||||||
new RegExFieldValidator(),
|
|
||||||
new DateFieldValidator(),
|
|
||||||
new MinDateFieldValidator(),
|
|
||||||
new MaxDateFieldValidator()
|
|
||||||
];
|
|
||||||
|
|
||||||
this.validateForm();
|
this.validateForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +139,10 @@ export class FormModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFieldById(fieldId: string): FormFieldModel {
|
||||||
|
return this.getFormFields().find(field => field.id === fieldId);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: consider evaluating and caching once the form is loaded
|
// TODO: consider evaluating and caching once the form is loaded
|
||||||
getFormFields(): FormFieldModel[] {
|
getFormFields(): FormFieldModel[] {
|
||||||
let result: FormFieldModel[] = [];
|
let result: FormFieldModel[] = [];
|
||||||
|
@ -169,6 +169,7 @@ The component shows the details of the task id passed in input
|
|||||||
| showInvolvePeople | boolean | true | Toggle `Involve People` feature for Header component |
|
| showInvolvePeople | boolean | true | Toggle `Involve People` feature for Header component |
|
||||||
| showComments | boolean | true | Toggle `Comments` feature for Header component |
|
| showComments | boolean | true | Toggle `Comments` feature for Header component |
|
||||||
| showChecklist | boolean | true | Toggle `Checklist` feature for Header component |
|
| showChecklist | boolean | true | Toggle `Checklist` feature for Header component |
|
||||||
|
| fieldValidators | FormFieldValidator[] | [] | Field validators for use with the form. |
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
[disableCompleteButton]="!isAssignedToMe()"
|
[disableCompleteButton]="!isAssignedToMe()"
|
||||||
[showSaveButton]="showFormSaveButton"
|
[showSaveButton]="showFormSaveButton"
|
||||||
[readOnly]="readOnlyForm"
|
[readOnly]="readOnlyForm"
|
||||||
|
[fieldValidators]="fieldValidators"
|
||||||
(formSaved)='onFormSaved($event)'
|
(formSaved)='onFormSaved($event)'
|
||||||
(formCompleted)='onFormCompleted($event)'
|
(formCompleted)='onFormCompleted($event)'
|
||||||
(formContentClicked)='onFormContentClick($event)'
|
(formContentClicked)='onFormContentClick($event)'
|
||||||
|
@ -26,7 +26,7 @@ import { Component,
|
|||||||
TemplateRef,
|
TemplateRef,
|
||||||
ViewChild
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { ContentLinkModel, FormModel, FormOutcomeEvent } from 'ng2-activiti-form';
|
import { ContentLinkModel, FormFieldValidator, FormModel, FormOutcomeEvent } from 'ng2-activiti-form';
|
||||||
import { AlfrescoAuthenticationService, AlfrescoTranslationService, CardViewUpdateService, ClickNotification, UpdateNotification } from 'ng2-alfresco-core';
|
import { AlfrescoAuthenticationService, AlfrescoTranslationService, CardViewUpdateService, ClickNotification, UpdateNotification } from 'ng2-alfresco-core';
|
||||||
import { TaskQueryRequestRepresentationModel } from '../models/filter.model';
|
import { TaskQueryRequestRepresentationModel } from '../models/filter.model';
|
||||||
import { TaskDetailsModel } from '../models/task-details.model';
|
import { TaskDetailsModel } from '../models/task-details.model';
|
||||||
@ -96,6 +96,9 @@ export class TaskDetailsComponent implements OnInit, OnChanges {
|
|||||||
@Input()
|
@Input()
|
||||||
peopleIconImageUrl: string = require('../assets/images/user.jpg');
|
peopleIconImageUrl: string = require('../assets/images/user.jpg');
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
fieldValidators: FormFieldValidator[] = [];
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
formSaved: EventEmitter<FormModel> = new EventEmitter<FormModel>();
|
formSaved: EventEmitter<FormModel> = new EventEmitter<FormModel>();
|
||||||
|
|
||||||
|
@ -48,7 +48,6 @@ export class TaskHeaderComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
console.log('change van:', changes, this.taskDetails);
|
|
||||||
this.refreshData();
|
this.refreshData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user