mirror of
https://github.com/SuiteCRM/SuiteCRM-Core.git
synced 2025-08-29 07:50:08 +08:00
Restructure front end filters setup
- Use FieldManager - Change ValidationManager to support save and filter validation - Use reactive forms formControl in varchar filter - Add null checks to datetime formatter - Add field type to criteria - Set form control value on field init - display messages for edit or filter modes - Validate filter input - Display warning messages when not valid - Adjust karma / jasmine tests
This commit is contained in:
parent
0916d14a5c
commit
61de0618ea
15 changed files with 270 additions and 93 deletions
|
@ -27,11 +27,15 @@ export class BaseFieldComponent implements FieldComponentInterface {
|
|||
newValue = this.typeFormatter.toInternalFormat(this.field.type, newValue);
|
||||
}
|
||||
|
||||
this.field.value = newValue;
|
||||
this.setFieldValue(newValue);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
protected setFieldValue(newValue): void {
|
||||
this.field.value = newValue;
|
||||
}
|
||||
|
||||
protected unsubscribeAll(): void {
|
||||
this.subs.forEach(sub => sub.unsubscribe());
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ class FieldTestHostComponent {
|
|||
{field: buildField({type: 'varchar', value: 'My Varchar'}), mode: 'list', expected: 'My Varchar'},
|
||||
{field: buildField({type: 'varchar', value: 'My Varchar'}), mode: 'edit', expected: 'My Varchar'},
|
||||
{
|
||||
field: buildField({type: 'varchar', criteria: {values: ['test'], operator: '='}}),
|
||||
field: buildField({type: 'varchar', value: 'test', criteria: {values: ['test'], operator: '='}}),
|
||||
mode: 'filter',
|
||||
expected: 'test'
|
||||
},
|
||||
|
|
|
@ -50,7 +50,7 @@ export class FieldComponent {
|
|||
}
|
||||
|
||||
isEdit(): boolean {
|
||||
return this.mode === 'edit';
|
||||
return this.mode === 'edit' || this.mode === 'filter';
|
||||
}
|
||||
|
||||
getLink(): string {
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
<input type="text" [ngClass]="klass" [(ngModel)]="value">
|
||||
<input [class.is-invalid]="field.formControl.invalid && field.formControl.touched"
|
||||
[formControl]="field.formControl"
|
||||
[ngClass]="klass"
|
||||
type="text">
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {Component} from '@angular/core';
|
||||
import {VarcharFilterFieldComponent} from './filter.component';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {Field} from '@app-common/record/field.model';
|
||||
import {UserPreferenceStore} from '@store/user-preference/user-preference.store';
|
||||
import {userPreferenceStoreMock} from '@store/user-preference/user-preference.store.spec.mock';
|
||||
|
@ -12,6 +11,9 @@ import {datetimeFormatterMock} from '@services/formatters/datetime/datetime-form
|
|||
import {DateFormatter} from '@services/formatters/datetime/date-formatter.service';
|
||||
import {dateFormatterMock} from '@services/formatters/datetime/date-formatter.service.spec.mock';
|
||||
import {CurrencyFormatter} from '@services/formatters/currency/currency-formatter.service';
|
||||
import {VarcharFilterFieldModule} from '@fields/varchar/templates/filter/filter.module';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {FormControl} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'varchar-filter-field-test-host-component',
|
||||
|
@ -20,10 +22,12 @@ import {CurrencyFormatter} from '@services/formatters/currency/currency-formatte
|
|||
class VarcharFilterFieldTestHostComponent {
|
||||
field: Field = {
|
||||
type: 'varchar',
|
||||
value: 'test filter value',
|
||||
criteria: {
|
||||
values: ['test filter value'],
|
||||
operator: '='
|
||||
}
|
||||
},
|
||||
formControl: new FormControl('test filter value')
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -38,7 +42,8 @@ describe('VarcharFilterFieldComponent', () => {
|
|||
VarcharFilterFieldComponent,
|
||||
],
|
||||
imports: [
|
||||
FormsModule
|
||||
VarcharFilterFieldModule,
|
||||
BrowserAnimationsModule
|
||||
],
|
||||
providers: [
|
||||
{provide: UserPreferenceStore, useValue: userPreferenceStoreMock},
|
||||
|
@ -70,7 +75,7 @@ describe('VarcharFilterFieldComponent', () => {
|
|||
|
||||
it('should have update input when field changes', async(() => {
|
||||
expect(testHostComponent).toBeTruthy();
|
||||
testHostComponent.field.criteria.values = ['New Field value'];
|
||||
testHostComponent.field.formControl.setValue('New Field value');
|
||||
|
||||
testHostFixture.detectChanges();
|
||||
testHostFixture.whenStable().then(() => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {Component} from '@angular/core';
|
||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||
import {BaseFieldComponent} from '@fields/base/base-field.component';
|
||||
import {DataTypeFormatter} from '@services/formatters/data-type.formatter.service';
|
||||
|
||||
|
@ -7,23 +7,31 @@ import {DataTypeFormatter} from '@services/formatters/data-type.formatter.servic
|
|||
templateUrl: './filter.component.html',
|
||||
styleUrls: []
|
||||
})
|
||||
export class VarcharFilterFieldComponent extends BaseFieldComponent {
|
||||
export class VarcharFilterFieldComponent extends BaseFieldComponent implements OnInit, OnDestroy {
|
||||
|
||||
constructor(protected typeFormatter: DataTypeFormatter) {
|
||||
super(typeFormatter);
|
||||
}
|
||||
|
||||
get value(): string {
|
||||
ngOnInit(): void {
|
||||
let current = '';
|
||||
|
||||
if (this.field.criteria.values && this.field.criteria.values.length > 0) {
|
||||
current = this.field.criteria.values[0];
|
||||
}
|
||||
|
||||
return current;
|
||||
this.field.value = current;
|
||||
const formattedValue = this.typeFormatter.toUserFormat(this.field.type, current, {mode: 'edit'});
|
||||
this.field.formControl.setValue(formattedValue);
|
||||
|
||||
this.subscribeValueChanges();
|
||||
}
|
||||
|
||||
set value(newValue: string) {
|
||||
ngOnDestroy(): void {
|
||||
this.unsubscribeAll();
|
||||
}
|
||||
|
||||
protected setFieldValue(newValue): void {
|
||||
this.field.value = newValue;
|
||||
this.field.criteria.operator = '=';
|
||||
this.field.criteria.values = [newValue];
|
||||
|
|
|
@ -3,7 +3,7 @@ import {CommonModule} from '@angular/common';
|
|||
|
||||
import {AppManagerModule} from '@base/app-manager/app-manager.module';
|
||||
import {VarcharFilterFieldComponent} from './filter.component';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
|
||||
|
||||
@NgModule({
|
||||
declarations: [VarcharFilterFieldComponent],
|
||||
|
@ -11,7 +11,8 @@ import {FormsModule} from '@angular/forms';
|
|||
imports: [
|
||||
CommonModule,
|
||||
AppManagerModule.forChild(VarcharFilterFieldComponent),
|
||||
FormsModule
|
||||
FormsModule,
|
||||
ReactiveFormsModule
|
||||
]
|
||||
})
|
||||
export class VarcharFilterFieldModule {
|
||||
|
|
|
@ -3,6 +3,7 @@ import {BulkActionsMap} from '@app-common/actions/bulk-action.model';
|
|||
import {LineAction} from '@app-common/actions/line-action.model';
|
||||
import {ChartTypesMap} from '@app-common/containers/chart/chart.model';
|
||||
import {WidgetMetadata} from '@app-common/metadata/widget.metadata';
|
||||
import {FieldDefinition} from '@app-common/record/field.model';
|
||||
|
||||
export interface ListViewMeta {
|
||||
fields: ColumnDefinition[];
|
||||
|
@ -33,6 +34,7 @@ export interface SearchMetaField {
|
|||
label?: string;
|
||||
default?: boolean;
|
||||
options?: string;
|
||||
fieldDefinition?: FieldDefinition;
|
||||
}
|
||||
|
||||
export interface SearchMeta {
|
||||
|
|
|
@ -7,7 +7,7 @@ export interface AttributeMap {
|
|||
|
||||
export interface Record {
|
||||
id?: string;
|
||||
type: string;
|
||||
type?: string;
|
||||
module: string;
|
||||
attributes: AttributeMap;
|
||||
fields?: FieldMap;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export interface SearchCriteriaFieldFilter {
|
||||
field?: string;
|
||||
fieldType?: string;
|
||||
operator: string;
|
||||
values?: string[];
|
||||
start?: string;
|
||||
|
|
|
@ -14,6 +14,7 @@ import {LanguageStore} from '@store/language/language.store';
|
|||
import {languageStoreMock} from '@store/language/language.store.spec.mock';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {ApolloTestingModule} from 'apollo-angular/testing';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
|
||||
describe('ListFilterComponent', () => {
|
||||
let testHostComponent: ListFilterComponent;
|
||||
|
@ -31,7 +32,8 @@ describe('ListFilterComponent', () => {
|
|||
DropdownButtonModule,
|
||||
FieldGridModule,
|
||||
RouterTestingModule,
|
||||
ApolloTestingModule
|
||||
ApolloTestingModule,
|
||||
BrowserAnimationsModule
|
||||
],
|
||||
providers: [
|
||||
{provide: ListViewStore, useValue: listviewStoreMock},
|
||||
|
|
|
@ -5,10 +5,15 @@ import {DropdownButtonInterface} from '@components/dropdown-button/dropdown-butt
|
|||
import {ButtonInterface} from '@components/button/button.model';
|
||||
import {deepClone} from '@base/app-common/utils/object-utils';
|
||||
import {combineLatest, Observable} from 'rxjs';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {Field} from '@app-common/record/field.model';
|
||||
import {filter, map, startWith, take} from 'rxjs/operators';
|
||||
import {Field, FieldMap} from '@app-common/record/field.model';
|
||||
import {SearchCriteria, SearchCriteriaFieldFilter} from '@app-common/views/list/search-criteria.model';
|
||||
import {Filter, SearchMetaField} from '@app-common/metadata/list.metadata.model';
|
||||
import {FieldManager} from '@services/record/field/field.manager';
|
||||
import {ViewFieldDefinition} from '@app-common/metadata/metadata.model';
|
||||
import {Record} from '@app-common/record/record.model';
|
||||
import {AbstractControl, FormGroup} from '@angular/forms';
|
||||
import {MessageService} from '@services/message/message.service';
|
||||
|
||||
export interface FilterDataSource {
|
||||
getFilter(): Observable<Filter>;
|
||||
|
@ -34,8 +39,14 @@ export class ListFilterComponent implements OnInit {
|
|||
searchCriteria: SearchCriteria;
|
||||
|
||||
vm$: Observable<any>;
|
||||
private record: Record;
|
||||
|
||||
constructor(protected listStore: ListViewStore, protected language: LanguageStore) {
|
||||
constructor(
|
||||
protected listStore: ListViewStore,
|
||||
protected language: LanguageStore,
|
||||
protected fieldManager: FieldManager,
|
||||
protected message: MessageService
|
||||
) {
|
||||
|
||||
this.vm$ = combineLatest([listStore.criteria$, listStore.metadata$]).pipe(
|
||||
map(([criteria, metadata]) => {
|
||||
|
@ -51,6 +62,11 @@ export class ListFilterComponent implements OnInit {
|
|||
|
||||
this.reset();
|
||||
|
||||
this.record = {
|
||||
module: this.listStore.getModuleName(),
|
||||
attributes: {}
|
||||
} as Record;
|
||||
|
||||
this.initFields();
|
||||
this.initGridButtons();
|
||||
this.initHeaderButtons();
|
||||
|
@ -72,15 +88,23 @@ export class ListFilterComponent implements OnInit {
|
|||
}
|
||||
|
||||
const searchFields = searchMeta.layout[type];
|
||||
const fields = {} as FieldMap;
|
||||
const formControls = {} as { [key: string]: AbstractControl };
|
||||
|
||||
Object.keys(searchFields).forEach(key => {
|
||||
const name = searchFields[key].name;
|
||||
|
||||
fields[name] = this.buildField(searchFields[key], languages, searchCriteria);
|
||||
formControls[name] = fields[name].formControl;
|
||||
|
||||
if (name.includes('_only')) {
|
||||
this.special.push(this.buildField(searchFields[key], languages, searchCriteria));
|
||||
this.special.push(fields[name]);
|
||||
} else {
|
||||
this.fields.push(this.buildField(searchFields[key], languages, searchCriteria));
|
||||
this.fields.push(fields[name]);
|
||||
}
|
||||
});
|
||||
|
||||
this.record.formGroup = new FormGroup(formControls);
|
||||
}
|
||||
|
||||
protected reset(): void {
|
||||
|
@ -128,21 +152,34 @@ export class ListFilterComponent implements OnInit {
|
|||
}
|
||||
|
||||
protected buildField(searchField: SearchMetaField, languages: LanguageStrings, searchCriteria: SearchCriteria): Field {
|
||||
const module = this.listStore.appState.module;
|
||||
|
||||
const fieldName = searchField.name;
|
||||
this.searchCriteria.filters[fieldName] = this.initFieldFilter(searchCriteria, fieldName);
|
||||
const type = searchField.type;
|
||||
this.searchCriteria.filters[fieldName] = this.initFieldFilter(searchCriteria, fieldName, type);
|
||||
|
||||
return {
|
||||
type: 'varchar',
|
||||
value: '',
|
||||
const definition = {
|
||||
name: searchField.name,
|
||||
label: this.language.getFieldLabel(searchField.label, module, languages),
|
||||
criteria: this.searchCriteria.filters[fieldName]
|
||||
} as Field;
|
||||
label: searchField.label,
|
||||
type,
|
||||
fieldDefinition: {}
|
||||
} as ViewFieldDefinition;
|
||||
|
||||
if (searchField.fieldDefinition) {
|
||||
definition.fieldDefinition = searchField.fieldDefinition;
|
||||
}
|
||||
|
||||
if (type === 'bool' || type === 'boolean') {
|
||||
definition.fieldDefinition.options = 'dom_int_bool';
|
||||
}
|
||||
|
||||
|
||||
const field = this.fieldManager.buildFilterField(this.record, definition, this.language);
|
||||
|
||||
field.criteria = this.searchCriteria.filters[fieldName];
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
protected initFieldFilter(searchCriteria: SearchCriteria, fieldName: string): SearchCriteriaFieldFilter {
|
||||
protected initFieldFilter(searchCriteria: SearchCriteria, fieldName: string, fieldType: string): SearchCriteriaFieldFilter {
|
||||
let fieldCriteria: SearchCriteriaFieldFilter;
|
||||
|
||||
if (searchCriteria.filters[fieldName]) {
|
||||
|
@ -150,8 +187,9 @@ export class ListFilterComponent implements OnInit {
|
|||
} else {
|
||||
fieldCriteria = {
|
||||
field: fieldName,
|
||||
fieldType,
|
||||
operator: '',
|
||||
values: [],
|
||||
values: []
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -159,8 +197,28 @@ export class ListFilterComponent implements OnInit {
|
|||
}
|
||||
|
||||
protected applyFilter(): void {
|
||||
this.listStore.showFilters = false;
|
||||
this.listStore.updateSearchCriteria(this.searchCriteria);
|
||||
this.validate().pipe(take(1)).subscribe(valid => {
|
||||
|
||||
if (valid) {
|
||||
this.listStore.showFilters = false;
|
||||
this.listStore.updateSearchCriteria(this.searchCriteria);
|
||||
return;
|
||||
}
|
||||
|
||||
this.message.addWarningMessageByKey('LBL_VALIDATION_ERRORS');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected validate(): Observable<boolean> {
|
||||
|
||||
this.record.formGroup.markAllAsTouched();
|
||||
return this.record.formGroup.statusChanges.pipe(
|
||||
startWith(this.record.formGroup.status),
|
||||
filter(status => status !== 'PENDING'),
|
||||
take(1),
|
||||
map(status => status === 'VALID')
|
||||
);
|
||||
}
|
||||
|
||||
protected clearFilter(): void {
|
||||
|
|
|
@ -91,7 +91,17 @@ export class DatetimeFormatter implements Formatter {
|
|||
}
|
||||
|
||||
toUserFormat(dateString: string): string {
|
||||
return formatDate(dateString, this.getUserFormat(), this.locale);
|
||||
if (!dateString) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const dateTime = this.toDateTime(dateString);
|
||||
|
||||
if (!dateTime.isValid) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return formatDate(dateTime.toJSDate(), this.getUserFormat(), this.locale);
|
||||
}
|
||||
|
||||
toInternalFormat(dateString: string): string {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import {Record} from '@app-common/record/record.model';
|
||||
import {ViewFieldDefinition} from '@app-common/metadata/metadata.model';
|
||||
import {LanguageStore} from '@store/language/language.store';
|
||||
import {FormControl} from '@angular/forms';
|
||||
import {AsyncValidatorFn, FormControl, ValidatorFn} from '@angular/forms';
|
||||
import {Field, FieldDefinition} from '@app-common/record/field.model';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {ValidationManager} from '@services/record/validation/validation.manager';
|
||||
|
@ -28,14 +28,40 @@ export class FieldManager {
|
|||
public buildField(record: Record, viewField: ViewFieldDefinition, language: LanguageStore = null): Field {
|
||||
|
||||
const definition = (viewField && viewField.fieldDefinition) || {} as FieldDefinition;
|
||||
const {value, valueList} = this.parseValue(viewField, definition, record);
|
||||
const {validators, asyncValidators} = this.getValidators(record, viewField);
|
||||
|
||||
return this.setupField(viewField, value, valueList, record, definition, validators, asyncValidators, language);
|
||||
}
|
||||
|
||||
public buildFilterField(record: Record, viewField: ViewFieldDefinition, language: LanguageStore = null): Field {
|
||||
|
||||
const definition = (viewField && viewField.fieldDefinition) || {} as FieldDefinition;
|
||||
const {value, valueList} = this.parseValue(viewField, definition, record);
|
||||
const {validators, asyncValidators} = this.getFilterValidators(record, viewField);
|
||||
|
||||
return this.setupField(viewField, value, valueList, record, definition, validators, asyncValidators, language);
|
||||
}
|
||||
|
||||
public getFieldLabel(label: string, module: string, language: LanguageStore): string {
|
||||
const languages = language.getLanguageStrings();
|
||||
return language.getFieldLabel(label, module, languages);
|
||||
}
|
||||
|
||||
protected parseValue(
|
||||
viewField: ViewFieldDefinition,
|
||||
definition: FieldDefinition,
|
||||
record: Record
|
||||
): { value: string; valueList: string[] } {
|
||||
|
||||
const type = (viewField && viewField.type) || '';
|
||||
const source = (definition && definition.source) || '';
|
||||
const rname = (definition && definition.rname) || 'name';
|
||||
const viewName = viewField.name || '';
|
||||
let value;
|
||||
let valueList = null;
|
||||
let value: string;
|
||||
let valueList: string[] = null;
|
||||
|
||||
if (!viewName) {
|
||||
if (!viewName || !record.attributes[viewName]) {
|
||||
value = '';
|
||||
} else if (type === 'relate' && source === 'non-db' && rname !== '') {
|
||||
value = record.attributes[viewName][rname];
|
||||
|
@ -48,8 +74,40 @@ export class FieldManager {
|
|||
value = null;
|
||||
}
|
||||
|
||||
const validators = this.validationManager.getValidations(record.module, viewField, record);
|
||||
const asyncValidators = this.validationManager.getAsyncValidations(record.module, viewField, record);
|
||||
return {value, valueList};
|
||||
}
|
||||
|
||||
protected getValidators(
|
||||
record: Record,
|
||||
viewField: ViewFieldDefinition
|
||||
): { validators: ValidatorFn[]; asyncValidators: AsyncValidatorFn[] } {
|
||||
|
||||
const validators = this.validationManager.getSaveValidations(record.module, viewField, record);
|
||||
const asyncValidators = this.validationManager.getAsyncSaveValidations(record.module, viewField, record);
|
||||
return {validators, asyncValidators};
|
||||
}
|
||||
|
||||
protected getFilterValidators(
|
||||
record: Record,
|
||||
viewField: ViewFieldDefinition
|
||||
): { validators: ValidatorFn[]; asyncValidators: AsyncValidatorFn[] } {
|
||||
|
||||
const validators = this.validationManager.getFilterValidations(record.module, viewField, record);
|
||||
const asyncValidators: AsyncValidatorFn[] = [];
|
||||
|
||||
return {validators, asyncValidators};
|
||||
}
|
||||
|
||||
protected setupField(
|
||||
viewField: ViewFieldDefinition,
|
||||
value: string,
|
||||
valueList: string[],
|
||||
record: Record,
|
||||
definition: FieldDefinition,
|
||||
validators: ValidatorFn[],
|
||||
asyncValidators: AsyncValidatorFn[],
|
||||
language: LanguageStore
|
||||
): Field {
|
||||
|
||||
const formattedValue = this.typeFormatter.toUserFormat(viewField.type, value, {mode: 'edit'});
|
||||
|
||||
|
@ -73,12 +131,6 @@ export class FieldManager {
|
|||
if (language) {
|
||||
field.label = this.getFieldLabel(viewField.label, record.module, language);
|
||||
}
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
public getFieldLabel(label: string, module: string, language: LanguageStore): string {
|
||||
const languages = language.getLanguageStrings();
|
||||
return language.getFieldLabel(label, module, languages);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import {Record} from '@app-common/record/record.model';
|
|||
import {ViewFieldDefinition} from '@app-common/metadata/metadata.model';
|
||||
import {AsyncValidatorFn, ValidatorFn} from '@angular/forms';
|
||||
import {AsyncValidatorInterface} from '@services/record/validation/aync-validator.Interface';
|
||||
import {OverridableMap} from '@app-common/types/OverridableMap';
|
||||
import {MapEntry, OverridableMap} from '@app-common/types/OverridableMap';
|
||||
import {RequiredValidator} from '@services/record/validation/validators/required.validator';
|
||||
import {CurrencyValidator} from '@services/record/validation/validators/currency.validator';
|
||||
import {DateValidator} from '@services/record/validation/validators/date.validator';
|
||||
|
@ -16,25 +16,32 @@ import {PhoneValidator} from '@services/record/validation/validators/phone.valid
|
|||
import {RangeValidator} from '@services/record/validation/validators/range.validator';
|
||||
|
||||
export interface ValidationManagerInterface {
|
||||
registerValidator(module: string, key: string, validator: ValidatorInterface): void;
|
||||
registerSaveValidator(module: string, key: string, validator: ValidatorInterface): void;
|
||||
|
||||
excludeValidator(module: string, key: string): void;
|
||||
registerFilterValidator(module: string, key: string, validator: ValidatorInterface): void;
|
||||
|
||||
registerAsyncValidator(module: string, key: string, validator: AsyncValidatorInterface): void;
|
||||
excludeSaveValidator(module: string, key: string): void;
|
||||
|
||||
excludeAsyncValidator(module: string, key: string): void;
|
||||
excludeFilterValidator(module: string, key: string): void;
|
||||
|
||||
getValidations(module: string, viewField: ViewFieldDefinition, record: Record): ValidatorFn[];
|
||||
registerAsyncSaveValidator(module: string, key: string, validator: AsyncValidatorInterface): void;
|
||||
|
||||
getAsyncValidations(module: string, viewField: ViewFieldDefinition, record: Record): AsyncValidatorFn[];
|
||||
excludeAsyncSaveValidator(module: string, key: string): void;
|
||||
|
||||
getSaveValidations(module: string, viewField: ViewFieldDefinition, record: Record): ValidatorFn[];
|
||||
|
||||
getFilterValidations(module: string, viewField: ViewFieldDefinition, record: Record): ValidatorFn[];
|
||||
|
||||
getAsyncSaveValidations(module: string, viewField: ViewFieldDefinition, record: Record): AsyncValidatorFn[];
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ValidationManager implements ValidationManagerInterface {
|
||||
protected validators: OverridableMap<ValidatorInterface>;
|
||||
protected asyncValidators: OverridableMap<AsyncValidatorInterface>;
|
||||
protected saveValidators: OverridableMap<ValidatorInterface>;
|
||||
protected asyncSaveValidators: OverridableMap<AsyncValidatorInterface>;
|
||||
protected filterValidators: OverridableMap<ValidatorInterface>;
|
||||
|
||||
constructor(
|
||||
protected requiredValidator: RequiredValidator,
|
||||
|
@ -48,57 +55,66 @@ export class ValidationManager implements ValidationManagerInterface {
|
|||
protected phoneValidator: PhoneValidator,
|
||||
) {
|
||||
|
||||
this.validators = new OverridableMap<ValidatorInterface>();
|
||||
this.asyncValidators = new OverridableMap<AsyncValidatorInterface>();
|
||||
this.saveValidators = new OverridableMap<ValidatorInterface>();
|
||||
this.asyncSaveValidators = new OverridableMap<AsyncValidatorInterface>();
|
||||
this.filterValidators = new OverridableMap<ValidatorInterface>();
|
||||
|
||||
this.validators.addEntry('default', 'required', requiredValidator);
|
||||
this.validators.addEntry('default', 'range', rangeValidator);
|
||||
this.validators.addEntry('default', 'currency', currencyValidator);
|
||||
this.validators.addEntry('default', 'date', dateValidator);
|
||||
this.validators.addEntry('default', 'datetime', datetimeValidator);
|
||||
this.validators.addEntry('default', 'email', emailValidator);
|
||||
this.validators.addEntry('default', 'float', floatValidator);
|
||||
this.validators.addEntry('default', 'int', intValidator);
|
||||
this.validators.addEntry('default', 'phone', phoneValidator);
|
||||
this.saveValidators.addEntry('default', 'required', requiredValidator);
|
||||
this.saveValidators.addEntry('default', 'range', rangeValidator);
|
||||
this.saveValidators.addEntry('default', 'currency', currencyValidator);
|
||||
this.saveValidators.addEntry('default', 'date', dateValidator);
|
||||
this.saveValidators.addEntry('default', 'datetime', datetimeValidator);
|
||||
this.saveValidators.addEntry('default', 'email', emailValidator);
|
||||
this.saveValidators.addEntry('default', 'float', floatValidator);
|
||||
this.saveValidators.addEntry('default', 'int', intValidator);
|
||||
this.saveValidators.addEntry('default', 'phone', phoneValidator);
|
||||
|
||||
this.filterValidators.addEntry('default', 'date', dateValidator);
|
||||
this.filterValidators.addEntry('default', 'datetime', datetimeValidator);
|
||||
this.filterValidators.addEntry('default', 'float', floatValidator);
|
||||
this.filterValidators.addEntry('default', 'currency', currencyValidator);
|
||||
this.filterValidators.addEntry('default', 'int', intValidator);
|
||||
this.filterValidators.addEntry('default', 'phone', phoneValidator);
|
||||
}
|
||||
|
||||
public registerValidator(module: string, key: string, validator: ValidatorInterface): void {
|
||||
this.validators.addEntry(module, key, validator);
|
||||
public registerSaveValidator(module: string, key: string, validator: ValidatorInterface): void {
|
||||
this.filterValidators.addEntry(module, key, validator);
|
||||
}
|
||||
|
||||
public excludeValidator(module: string, key: string): void {
|
||||
this.validators.excludeEntry(module, key);
|
||||
public registerFilterValidator(module: string, key: string, validator: ValidatorInterface): void {
|
||||
this.saveValidators.addEntry(module, key, validator);
|
||||
}
|
||||
|
||||
public registerAsyncValidator(module: string, key: string, validator: AsyncValidatorInterface): void {
|
||||
this.asyncValidators.addEntry(module, key, validator);
|
||||
public excludeSaveValidator(module: string, key: string): void {
|
||||
this.saveValidators.excludeEntry(module, key);
|
||||
}
|
||||
|
||||
public excludeAsyncValidator(module: string, key: string): void {
|
||||
this.validators.excludeEntry(module, key);
|
||||
public excludeFilterValidator(module: string, key: string): void {
|
||||
this.filterValidators.excludeEntry(module, key);
|
||||
}
|
||||
|
||||
public getValidations(module: string, viewField: ViewFieldDefinition, record: Record): ValidatorFn[] {
|
||||
let validations = [];
|
||||
|
||||
const entries = this.validators.getGroupEntries(module);
|
||||
|
||||
Object.keys(entries).forEach(validatorKey => {
|
||||
|
||||
const validator = entries[validatorKey];
|
||||
|
||||
if (validator.applies(record, viewField)) {
|
||||
validations = validations.concat(validator.getValidator(viewField, record));
|
||||
}
|
||||
});
|
||||
|
||||
return validations;
|
||||
public registerAsyncSaveValidator(module: string, key: string, validator: AsyncValidatorInterface): void {
|
||||
this.asyncSaveValidators.addEntry(module, key, validator);
|
||||
}
|
||||
|
||||
public getAsyncValidations(module: string, viewField: ViewFieldDefinition, record: Record): AsyncValidatorFn[] {
|
||||
public excludeAsyncSaveValidator(module: string, key: string): void {
|
||||
this.saveValidators.excludeEntry(module, key);
|
||||
}
|
||||
|
||||
public getSaveValidations(module: string, viewField: ViewFieldDefinition, record: Record): ValidatorFn[] {
|
||||
const entries = this.saveValidators.getGroupEntries(module);
|
||||
return this.filterValidations(entries, record, viewField);
|
||||
}
|
||||
|
||||
public getFilterValidations(module: string, viewField: ViewFieldDefinition, record: Record): ValidatorFn[] {
|
||||
const entries = this.filterValidators.getGroupEntries(module);
|
||||
return this.filterValidations(entries, record, viewField);
|
||||
}
|
||||
|
||||
public getAsyncSaveValidations(module: string, viewField: ViewFieldDefinition, record: Record): AsyncValidatorFn[] {
|
||||
const validations = [];
|
||||
|
||||
const entries = this.asyncValidators.getGroupEntries(module);
|
||||
const entries = this.asyncSaveValidators.getGroupEntries(module);
|
||||
|
||||
Object.keys(entries).forEach(validatorKey => {
|
||||
|
||||
|
@ -111,4 +127,19 @@ export class ValidationManager implements ValidationManagerInterface {
|
|||
|
||||
return validations;
|
||||
}
|
||||
|
||||
protected filterValidations(entries: MapEntry<ValidatorInterface>, record: Record, viewField: ViewFieldDefinition): ValidatorFn[] {
|
||||
let validations = [];
|
||||
|
||||
Object.keys(entries).forEach(validatorKey => {
|
||||
|
||||
const validator = entries[validatorKey];
|
||||
|
||||
if (validator.applies(record, viewField)) {
|
||||
validations = validations.concat(validator.getValidator(viewField, record));
|
||||
}
|
||||
});
|
||||
|
||||
return validations;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue