changes desciption editor form field logic to apply validation from form control instead of required html attribute

This commit is contained in:
Diamantis Tziotzios 2024-06-06 20:19:22 +03:00
parent d606cd4058
commit eaa802872a
9 changed files with 194 additions and 108 deletions

View File

@ -76,7 +76,7 @@ export class DescriptionTemplatePreviewDialogComponent extends BaseComponent imp
}
buildForm() {
this.formGroup = this.editorModel.buildForm(null, true);
this.formGroup = this.editorModel.buildForm(null, true, this.visibilityRulesService);
this.previewPropertiesFormGroup = this.editorModel.properties.buildForm() as UntypedFormGroup;
this.visibilityRulesService.setContext(this.descriptionTemplate.definition, this.previewPropertiesFormGroup);
}

View File

@ -220,7 +220,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
permissionPerSection => {
this.canEdit = permissionPerSection && permissionPerSection[this.item.dmpDescriptionTemplate.sectionId.toString()] && permissionPerSection[this.item.dmpDescriptionTemplate.sectionId.toString()].some(x => x === AppPermission.EditDescription);
this.canReview = permissionPerSection && permissionPerSection[this.item.dmpDescriptionTemplate.sectionId.toString()] && permissionPerSection[this.item.dmpDescriptionTemplate.sectionId.toString()].some(x => x === AppPermission.ReviewDescription);
this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !this.canEdit);
this.formGroup = this.editorModel.buildForm(null, this.isDeleted || !this.canEdit, this.visibilityRulesService);
if (this.item.descriptionTemplate?.definition) this.visibilityRulesService.setContext(this.item.descriptionTemplate.definition, this.formGroup.get('properties'));
if (this.item.descriptionTemplate?.definition) this.pageToFieldSetMap = this.mapPageToFieldSet(this.item.descriptionTemplate);;
@ -681,7 +681,7 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
this.initialTemplateId = descriptionTemplateId.toString();
this.editorModel.properties = new DescriptionPropertyDefinitionEditorModel(this.editorModel.validationErrorModel).fromModel(null, descriptionTemplate, null);
this.formGroup.setControl('properties', this.editorModel.buildProperties());
this.formGroup.setControl('properties', this.editorModel.buildProperties(this.visibilityRulesService));
this.item.descriptionTemplate = descriptionTemplate;
const sectionId = this.item.dmpDescriptionTemplate.sectionId;
@ -755,6 +755,8 @@ export class DescriptionEditorComponent extends BaseEditor<DescriptionEditorMode
finalize() {
this.formService.removeAllBackEndErrors(this.formGroup);
this.formService.touchAllFormFields(this.formGroup);
this.formService.validateAllFormFields(this.formGroup);
this.tocValidationService.validateForm();
if (!this.isFormValid()) {
this.dialog.open(FormValidationErrorsDialogComponent, {

View File

@ -1,15 +1,17 @@
import { FormControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { DescriptionStatus } from "@app/core/common/enum/description-status";
import { DescriptionTemplateFieldType } from "@app/core/common/enum/description-template-field-type";
import { DescriptionTemplateFieldValidationType } from "@app/core/common/enum/description-template-field-validation-type";
import { IsActive } from "@app/core/common/enum/is-active.enum";
import { DescriptionTemplate, DescriptionTemplateField, DescriptionTemplateFieldSet, DescriptionTemplateSection } from "@app/core/model/description-template/description-template";
import { Description, DescriptionExternalIdentifier, DescriptionExternalIdentifierPersist, DescriptionField, DescriptionFieldPersist, DescriptionPersist, DescriptionPropertyDefinition, DescriptionPropertyDefinitionFieldSet, DescriptionPropertyDefinitionFieldSetItem, DescriptionPropertyDefinitionFieldSetItemPersist, DescriptionPropertyDefinitionFieldSetPersist, DescriptionPropertyDefinitionPersist, DescriptionReference, DescriptionReferencePersist } from "@app/core/model/description/description";
import { ReferencePersist } from "@app/core/model/reference/reference";
import { BaseEditorModel } from "@common/base/base-form-editor-model";
import { BackendErrorValidator } from '@common/forms/validation/custom-validator';
import { BackendErrorValidator, RequiredWithVisibilityRulesValidator } from '@common/forms/validation/custom-validator';
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { Validation, ValidationContext } from '@common/forms/validation/validation-context';
import { Guid } from "@common/types/guid";
import { VisibilityRulesService } from "./description-form/visibility-rules/visibility-rules.service";
export class DescriptionEditorModel extends BaseEditorModel implements DescriptionPersist {
label: string;
@ -42,7 +44,7 @@ export class DescriptionEditorModel extends BaseEditorModel implements Descripti
return this;
}
buildForm(context: ValidationContext = null, disabled: boolean = false): UntypedFormGroup {
buildForm(context: ValidationContext = null, disabled: boolean = false, visibilityRulesService: VisibilityRulesService): UntypedFormGroup {
if (context == null) { context = this.createValidationContext(); }
return this.formBuilder.group({
@ -54,14 +56,15 @@ export class DescriptionEditorModel extends BaseEditorModel implements Descripti
status: [{ value: this.status, disabled: disabled }, context.getValidation('status').validators],
description: [{ value: this.description, disabled: disabled }, context.getValidation('description').validators],
tags: [{ value: this.tags, disabled: disabled }, context.getValidation('tags').validators],
properties: this.buildProperties(),
properties: this.buildProperties(visibilityRulesService),
hash: [{ value: this.hash, disabled: disabled }, context.getValidation('hash').validators]
});
}
buildProperties() {
buildProperties(visibilityRulesService: VisibilityRulesService) {
return this.properties.buildForm({
rootPath: `properties.`
rootPath: `properties.`,
visibilityRulesService: visibilityRulesService
});
}
@ -82,18 +85,37 @@ export class DescriptionEditorModel extends BaseEditorModel implements Descripti
return baseContext;
}
static reApplyPropertiesValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
}): void {
const { formGroup, validationErrorModel } = params;
const control = formGroup?.get('properties');
DescriptionPropertyDefinitionEditorModel.reapplyValidators({
formGroup: control.get('fieldSets') as UntypedFormGroup,
rootPath: `properties.`,
validationErrorModel: validationErrorModel
});
static getFieldValueControlName(fieldType: DescriptionTemplateFieldType, multipleSelect: boolean): string {
switch (fieldType) {
case DescriptionTemplateFieldType.FREE_TEXT:
case DescriptionTemplateFieldType.TEXT_AREA:
case DescriptionTemplateFieldType.UPLOAD:
case DescriptionTemplateFieldType.RICH_TEXT_AREA:
case DescriptionTemplateFieldType.RADIO_BOX:
return 'textValue';
case DescriptionTemplateFieldType.DATASET_IDENTIFIER:
case DescriptionTemplateFieldType.VALIDATION:
return 'externalIdentifier';
case DescriptionTemplateFieldType.DATE_PICKER:
return 'dateValue';
case DescriptionTemplateFieldType.CHECK_BOX:
case DescriptionTemplateFieldType.BOOLEAN_DECISION:
return 'booleanValue';
case DescriptionTemplateFieldType.INTERNAL_ENTRIES_DESCRIPTIONS:
if (multipleSelect) return 'textListValue';
else return 'textValue';
case DescriptionTemplateFieldType.INTERNAL_ENTRIES_DMPS:
if (multipleSelect) return 'textListValue';
else return 'textValue';
case DescriptionTemplateFieldType.REFERENCE_TYPES:
if (multipleSelect) return 'references';
else return 'reference';
case DescriptionTemplateFieldType.SELECT:
if (multipleSelect) return 'textListValue';
else return 'textValue';
case DescriptionTemplateFieldType.TAGS:
return 'tags';
}
}
}
@ -113,7 +135,8 @@ export class DescriptionPropertyDefinitionEditorModel implements DescriptionProp
buildForm(params?: {
context?: ValidationContext,
disabled?: boolean,
rootPath?: string
rootPath?: string,
visibilityRulesService: VisibilityRulesService
}): UntypedFormGroup {
let { context = null, disabled = false, rootPath } = params ?? {}
if (context == null) {
@ -128,7 +151,8 @@ export class DescriptionPropertyDefinitionEditorModel implements DescriptionProp
const fieldSetsFormGroup = this.formBuilder.group({});
if (this.fieldSets.size > 0) {
this.fieldSets.forEach((value, key) => fieldSetsFormGroup.addControl(key.toString(), value.buildForm({
rootPath: `${rootPath}fieldSets[${key}].`
rootPath: `${rootPath}fieldSets[${key}].`,
visibilityRulesService: params.visibilityRulesService
})), context.getValidation('fieldSets'));
formGroup.addControl('fieldSets', fieldSetsFormGroup);
}
@ -149,25 +173,6 @@ export class DescriptionPropertyDefinitionEditorModel implements DescriptionProp
return baseContext;
}
static reapplyValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
const keys = Object.keys(formGroup.value as Object);
keys.forEach((key) => {
const formArray = formGroup?.get(key);
DescriptionPropertyDefinitionFieldSetEditorModel.reapplyValidators({
formArray: formArray.get('items') as UntypedFormArray,
rootPath: `${rootPath}fieldSets[${key}].`,
validationErrorModel: validationErrorModel
})
});
}
private calculateProperties(item: DescriptionPropertyDefinition, descriptionTemplate: DescriptionTemplate, descriptionReferences: DescriptionReference[]): Map<string, DescriptionPropertyDefinitionFieldSetEditorModel> {
let result: Map<string, DescriptionPropertyDefinitionFieldSetEditorModel> = new Map<string, DescriptionPropertyDefinitionFieldSetEditorModel>();
if (descriptionTemplate) (
@ -279,7 +284,8 @@ export class DescriptionPropertyDefinitionFieldSetEditorModel implements Descrip
buildForm(params?: {
context?: ValidationContext,
disabled?: boolean,
rootPath?: string
rootPath?: string,
visibilityRulesService: VisibilityRulesService
}): UntypedFormGroup {
let { context = null, disabled = false, rootPath } = params ?? {}
if (context == null) {
@ -293,7 +299,8 @@ export class DescriptionPropertyDefinitionFieldSetEditorModel implements Descrip
items: this.formBuilder.array(
(this.items ?? []).map(
(item, index) => item.buildForm({
rootPath: `${rootPath}items[${index}].`
rootPath: `${rootPath}items[${index}].`,
visibilityRulesService: params.visibilityRulesService
})
), context.getValidation('items').validators
)
@ -317,14 +324,18 @@ export class DescriptionPropertyDefinitionFieldSetEditorModel implements Descrip
static reapplyValidators(params: {
formArray: UntypedFormArray,
validationErrorModel: ValidationErrorModel,
rootPath: string
rootPath: string,
fieldSetDefinition: DescriptionTemplateFieldSet,
visibilityRulesService: VisibilityRulesService
}): void {
const { validationErrorModel, rootPath, formArray } = params;
const { validationErrorModel, rootPath, formArray, fieldSetDefinition } = params;
formArray?.controls?.forEach(
(control, index) => DescriptionPropertyDefinitionFieldSetItemEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `${rootPath}items[${index}].`,
validationErrorModel: validationErrorModel
validationErrorModel: validationErrorModel,
fieldSetDefinition: fieldSetDefinition,
visibilityRulesService: params.visibilityRulesService
})
);
}
@ -359,7 +370,8 @@ export class DescriptionPropertyDefinitionFieldSetItemEditorModel implements Des
buildForm(params?: {
context?: ValidationContext,
disabled?: boolean,
rootPath?: string
rootPath?: string,
visibilityRulesService: VisibilityRulesService
}): UntypedFormGroup {
let { context = null, disabled = false, rootPath } = params ?? {}
if (context == null) {
@ -376,7 +388,9 @@ export class DescriptionPropertyDefinitionFieldSetItemEditorModel implements Des
const fieldsFormGroup = this.formBuilder.group({});
this.fields.forEach((value, key) => fieldsFormGroup.addControl(key.toString(), value.buildForm({
rootPath: `${rootPath}fields[${key}].`
rootPath: `${rootPath}fields[${key}].`,
visibilityRulesService: params.visibilityRulesService,
visibilityRulesKey: key + '_' + formGroup.get('ordinal').value
})), context.getValidation('fields')
)
formGroup.addControl('fields', fieldsFormGroup);
@ -403,10 +417,12 @@ export class DescriptionPropertyDefinitionFieldSetItemEditorModel implements Des
static reapplyValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
rootPath: string
rootPath: string,
fieldSetDefinition: DescriptionTemplateFieldSet,
visibilityRulesService: VisibilityRulesService
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
const { formGroup, rootPath, validationErrorModel, fieldSetDefinition } = params;
const context = DescriptionPropertyDefinitionFieldSetItemEditorModel.createValidationContext({
rootPath,
validationErrorModel
@ -419,7 +435,10 @@ export class DescriptionPropertyDefinitionFieldSetItemEditorModel implements Des
DescriptionFieldEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `${rootPath}fields[${key}].`,
validationErrorModel: validationErrorModel
validationErrorModel: validationErrorModel,
fieldDefinition: fieldSetDefinition.fields.find(x => x.id == key),
visibilityRulesService: params.visibilityRulesService,
visibilityRulesKey: key + '_' + formGroup.get('ordinal').value
})
});
@ -442,6 +461,8 @@ export class DescriptionFieldEditorModel implements DescriptionFieldPersist {
tags: string[] = [];
externalIdentifier?: DescriptionExternalIdentifierEditorModel = new DescriptionExternalIdentifierEditorModel(this.validationErrorModel);
fieldDefinition: DescriptionTemplateField;
protected formBuilder: UntypedFormBuilder = new UntypedFormBuilder();
constructor(
@ -449,6 +470,7 @@ export class DescriptionFieldEditorModel implements DescriptionFieldPersist {
) { }
public fromModel(item: DescriptionField, descriptionTemplateField: DescriptionTemplateField, descriptionReferences: DescriptionReference[]): DescriptionFieldEditorModel {
this.fieldDefinition = descriptionTemplateField;
if (item) {
this.textValue = item.textValue;
this.textListValue = item.textListValue;
@ -488,46 +510,89 @@ export class DescriptionFieldEditorModel implements DescriptionFieldPersist {
buildForm(params?: {
context?: ValidationContext,
disabled?: boolean,
rootPath?: string
rootPath?: string,
visibilityRulesService: VisibilityRulesService,
visibilityRulesKey: string
}): UntypedFormGroup {
let { context = null, disabled = false, rootPath } = params ?? {}
if (context == null) {
context = DescriptionFieldEditorModel.createValidationContext({
validationErrorModel: this.validationErrorModel,
rootPath
rootPath,
fieldDefinition: this.fieldDefinition,
visibilityRulesService: params.visibilityRulesService,
visibilityRulesKey: params.visibilityRulesKey
});
}
return this.formBuilder.group({
textValue: [{ value: this.textValue, disabled: disabled }, context.getValidation('textValue').validators],
textListValue: [{ value: this.textListValue, disabled: disabled }, context.getValidation('textListValue').validators],
dateValue: [{ value: this.dateValue, disabled: disabled }, context.getValidation('dateValue').validators],
booleanValue: [{ value: this.booleanValue, disabled: disabled }, context.getValidation('booleanValue').validators],
references: [{ value: this.references, disabled: disabled }, context.getValidation('references').validators],
reference: [{ value: this.reference, disabled: disabled }, context.getValidation('reference').validators],
tags: [{ value: this.tags, disabled: disabled }, context.getValidation('tags').validators],
externalIdentifier: this.externalIdentifier.buildForm({
const fieldType = this.fieldDefinition.data.fieldType;
const multipleSelect = this.fieldDefinition.data.multipleSelect;
const fieldValueControlName = DescriptionEditorModel.getFieldValueControlName(fieldType, multipleSelect);
const formGroup = this.formBuilder.group({});
switch (fieldType) {
case DescriptionTemplateFieldType.FREE_TEXT:
case DescriptionTemplateFieldType.TEXT_AREA:
case DescriptionTemplateFieldType.UPLOAD:
case DescriptionTemplateFieldType.RICH_TEXT_AREA:
case DescriptionTemplateFieldType.RADIO_BOX:
formGroup.addControl(fieldValueControlName, new FormControl({ value: this.textValue, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
case DescriptionTemplateFieldType.DATASET_IDENTIFIER:
case DescriptionTemplateFieldType.VALIDATION:
formGroup.addControl(fieldValueControlName, this.externalIdentifier.buildForm({
rootPath: `${rootPath}externalIdentifier.`
}),
});
}));
case DescriptionTemplateFieldType.DATE_PICKER:
formGroup.addControl(fieldValueControlName, new FormControl({ value: this.dateValue, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
case DescriptionTemplateFieldType.CHECK_BOX:
case DescriptionTemplateFieldType.BOOLEAN_DECISION:
formGroup.addControl(fieldValueControlName, new FormControl({ value: this.booleanValue, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
case DescriptionTemplateFieldType.INTERNAL_ENTRIES_DESCRIPTIONS:
if (multipleSelect) formGroup.addControl(fieldValueControlName, new FormControl({ value: this.textListValue, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
else formGroup.addControl(fieldValueControlName, new FormControl({ value: this.textValue, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
case DescriptionTemplateFieldType.INTERNAL_ENTRIES_DMPS:
if (multipleSelect) formGroup.addControl(fieldValueControlName, new FormControl({ value: this.textListValue, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
else formGroup.addControl(fieldValueControlName, new FormControl({ value: this.textValue, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
case DescriptionTemplateFieldType.REFERENCE_TYPES:
if (multipleSelect) formGroup.addControl(fieldValueControlName, new FormControl({ value: this.references, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
else formGroup.addControl(fieldValueControlName, new FormControl({ value: this.reference, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
case DescriptionTemplateFieldType.SELECT:
if (multipleSelect) formGroup.addControl(fieldValueControlName, new FormControl({ value: this.textListValue, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
else formGroup.addControl(fieldValueControlName, new FormControl({ value: this.textValue, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
case DescriptionTemplateFieldType.TAGS:
formGroup.addControl(fieldValueControlName, new FormControl({ value: this.tags, disabled: disabled }, context.getValidation(fieldValueControlName).validators));
}
return formGroup;
}
static createValidationContext(params: {
rootPath?: string,
validationErrorModel: ValidationErrorModel
validationErrorModel: ValidationErrorModel,
fieldDefinition: DescriptionTemplateField,
visibilityRulesService: VisibilityRulesService,
visibilityRulesKey: string
}): ValidationContext {
const { rootPath = '', validationErrorModel } = params;
const baseContext: ValidationContext = new ValidationContext();
const baseValidationArray: Validation[] = new Array<Validation>();
baseValidationArray.push({ key: 'textValue', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}textValue`)] });
baseValidationArray.push({ key: 'textListValue', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}textListValue`)] });
baseValidationArray.push({ key: 'dateValue', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}dateValue`)] });
baseValidationArray.push({ key: 'booleanValue', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}booleanValue`)] });
baseValidationArray.push({ key: 'references', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}references`)] });
baseValidationArray.push({ key: 'reference', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}references`)] });
baseValidationArray.push({ key: 'tags', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}tags`)] });
baseValidationArray.push({ key: 'externalIdentifier', validators: [BackendErrorValidator(validationErrorModel, `${rootPath}externalIdentifier`)] });
const fieldValueControlName = DescriptionEditorModel.getFieldValueControlName(params.fieldDefinition.data.fieldType, params.fieldDefinition.data.multipleSelect);
const validators = [];
validators.push(BackendErrorValidator(validationErrorModel, `${rootPath}${fieldValueControlName}`));
params.fieldDefinition.validations.forEach(validation => {
switch (validation) {
case DescriptionTemplateFieldValidationType.Required:
validators.push(RequiredWithVisibilityRulesValidator(params.visibilityRulesService, params.visibilityRulesKey));
break;
case DescriptionTemplateFieldValidationType.Url:
//TODO
break;
}
});
baseValidationArray.push({ key: fieldValueControlName, validators: validators });
baseContext.validation = baseValidationArray;
return baseContext;
}
@ -535,13 +600,20 @@ export class DescriptionFieldEditorModel implements DescriptionFieldPersist {
static reapplyValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
rootPath: string
rootPath: string,
fieldDefinition: DescriptionTemplateField,
visibilityRulesService: VisibilityRulesService,
visibilityRulesKey: string
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
const { formGroup, rootPath, validationErrorModel, fieldDefinition } = params;
const context = DescriptionFieldEditorModel.createValidationContext({
rootPath,
validationErrorModel
validationErrorModel,
fieldDefinition: fieldDefinition,
visibilityRulesService: params.visibilityRulesService,
visibilityRulesKey: params.visibilityRulesKey
});
['textValue', 'textListValue', 'dateValue', 'booleanValue'].forEach(keyField => {

View File

@ -86,7 +86,7 @@ export class DescriptionFormFieldSetComponent extends BaseComponent {
ordinal = Math.max(...properties.items.map(x => x.ordinal).filter(val => !isNaN(val))) + 1;
}
const item: DescriptionPropertyDefinitionFieldSetEditorModel = new DescriptionPropertyDefinitionEditorModel(this.validationErrorModel).calculateFieldSetProperties(this.fieldSet, ordinal, null, null);
formArray.push((item.buildForm({ rootPath: `properties.fieldSets[${this.fieldSet.id}].` }).get('items') as UntypedFormArray).at(0));
formArray.push((item.buildForm({ rootPath: `properties.fieldSets[${this.fieldSet.id}].`, visibilityRulesService: this.visibilityRulesService }).get('items') as UntypedFormArray).at(0));
this.visibilityRulesService.reloadVisibility();
}
@ -102,7 +102,9 @@ export class DescriptionFormFieldSetComponent extends BaseComponent {
{
formArray: formArray,
validationErrorModel: this.validationErrorModel,
rootPath: `properties.fieldSets[${this.fieldSet.id}].`
rootPath: `properties.fieldSets[${this.fieldSet.id}].`,
fieldSetDefinition: this.fieldSet,
visibilityRulesService: this.visibilityRulesService
}
);
formArray.markAsDirty();

View File

@ -11,7 +11,7 @@
<div class="col-12">
<mat-form-field class="w-100">
<mat-label>{{ field.data.label }}</mat-label>
<input matInput [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" placeholder="{{(field.data.label) + (isRequired? ' *': '')}}" [required]="isRequired">
<input matInput [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" placeholder="{{(field.data.label) + (isRequired? ' *': '')}}" >
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('pattern')">{{'GENERAL.VALIDATION.URL.MESSAGE' | translate}}</mat-error>
@ -31,14 +31,14 @@
<div class="row">
<mat-form-field class="col-md-12">
<ng-container *ngIf="field.data.multipleSelect">
<mat-select [formControl]="propertiesFormGroup?.get(field.id).get('textListValue')" placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [required]="isRequired" [multiple]="field.data.multipleSelect">
<mat-select [formControl]="propertiesFormGroup?.get(field.id).get('textListValue')" placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [multiple]="field.data.multipleSelect">
<mat-option *ngFor="let opt of field.data.options" [value]="opt.value">{{opt.label}}</mat-option>
</mat-select>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textListValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textListValue').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textListValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</ng-container>
<ng-container *ngIf="!(field.data.multipleSelect)">
<mat-select [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [required]="isRequired" [multiple]="field.data.multipleSelect">
<mat-select [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [multiple]="field.data.multipleSelect">
<mat-option *ngFor="let opt of field.data.options" [value]="opt.value">{{opt.label}}
</mat-option>
</mat-select>
@ -63,7 +63,7 @@
<ng-container *ngIf="!(field.data.multipleSelect)">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [configuration]="descriptionService.singleAutocompleteConfiguration" [required]="isRequired">
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [configuration]="descriptionService.singleAutocompleteConfiguration" >
</app-single-auto-complete>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -87,7 +87,7 @@
<ng-container *ngIf="!(field.data.multipleSelect)">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [configuration]="dmpService.singleAutocompleteConfiguration" [required]="isRequired">
<app-single-auto-complete placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [configuration]="dmpService.singleAutocompleteConfiguration" >
</app-single-auto-complete>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
@ -105,7 +105,7 @@
<div class="col-12">
<mat-form-field *ngSwitchCase="descriptionTemplateFieldTypeEnum.TEXT_AREA" class="w-100">
<mat-label>{{ field.data.label }}</mat-label>
<textarea matInput class="text-area" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" matTextareaAutosize matAutosizeMinRows="3" matAutosizeMaxRows="15" [required]="isRequired" placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}"></textarea>
<textarea matInput class="text-area" [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" matTextareaAutosize matAutosizeMinRows="3" matAutosizeMaxRows="15" placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}"></textarea>
<button mat-icon-button type="button" *ngIf="!propertiesFormGroup?.get(field.id).get('textValue').disabled && propertiesFormGroup?.get(field.id).get('textValue').value" matSuffix aria-label="Clear" (click)="this.propertiesFormGroup?.get(field.id).get('textValue').patchValue('')">
<mat-icon>close</mat-icon>
</button>
@ -116,7 +116,7 @@
<ng-container *ngSwitchCase="descriptionTemplateFieldTypeEnum.RICH_TEXT_AREA">
<div class="col-12">
<rich-text-editor-component [form]="propertiesFormGroup?.get(field.id).get('textValue')" [placeholder]="field.data.label" [required]="isRequired" [wrapperClasses]="'full-width editor ' +
<rich-text-editor-component [form]="propertiesFormGroup?.get(field.id).get('textValue')" [placeholder]="field.data.label" [wrapperClasses]="'full-width editor ' +
((isRequired && propertiesFormGroup?.get(field.id).get('textValue').touched && propertiesFormGroup?.get(field.id).get('textValue').hasError('required')) ? 'required' : '')" [editable]="!propertiesFormGroup?.get(field.id).get('textValue').disabled">
</rich-text-editor-component>
</div>
@ -148,7 +148,7 @@
</div>
</ng-container>
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.BOOLEAN_DECISION" class="col-12">
<mat-radio-group [formControl]="propertiesFormGroup?.get(field.id).get('booleanValue')" [required]="isRequired">
<mat-radio-group [formControl]="propertiesFormGroup?.get(field.id).get('booleanValue')" >
<mat-radio-button class="radio-button-item" [value]="true">{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.ACTIONS.YES" | translate }}</mat-radio-button>
<mat-radio-button class="radio-button-item" [value]="false">{{ "TYPES.DATASET-PROFILE-COMBO-BOX-TYPE.ACTIONS.NO" | translate }}</mat-radio-button>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('booleanValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('booleanValue').getError('backendError').message}}</mat-error>
@ -159,7 +159,7 @@
</div>
<div *ngSwitchCase="descriptionTemplateFieldTypeEnum.RADIO_BOX" class="col-12">
<mat-radio-group [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" [required]="isRequired">
<mat-radio-group [formControl]="propertiesFormGroup?.get(field.id).get('textValue')" >
<mat-radio-button *ngFor="let option of field.data.options let index = index" class="radio-button-item" [value]="option.value">{{option.label}}</mat-radio-button>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('textValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('textValue').getError('backendError').message}}</mat-error>
</mat-radio-group>
@ -170,7 +170,7 @@
<mat-form-field *ngSwitchCase="descriptionTemplateFieldTypeEnum.DATE_PICKER" class="col-12">
<mat-label>{{ field.data.label }}</mat-label>
<input matInput placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" class="table-input" [matDatepicker]="date" [required]="isRequired" [formControl]="propertiesFormGroup?.get(field.id).get('dateValue')">
<input matInput placeholder="{{ (field.data.label | translate) + (isRequired? ' *': '') }}" class="table-input" [matDatepicker]="date" [formControl]="propertiesFormGroup?.get(field.id).get('dateValue')">
<mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
<mat-datepicker #date></mat-datepicker>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('dateValue').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('dateValue').getError('backendError').message}}</mat-error>
@ -185,13 +185,13 @@
<div class="row" *ngIf="datasetIdInitialized">
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<input matInput class="col-md-12" [formControl]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier')" placeholder="{{(field.data.label) + (isRequired? ' *': '')}}" [required]="isRequired" [disabled]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').disabled">
<input matInput class="col-md-12" [formControl]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier')" placeholder="{{(field.data.label) + (isRequired? ' *': '')}}" [disabled]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').disabled">
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>
<mat-form-field class="col-md-12">
<mat-label>{{ field.data.label }}</mat-label>
<mat-select class="col-md-12" [formControl]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('type')" [placeholder]="('TYPES.DATASET-PROFILE-IDENTIFIER.IDENTIFIER-TYPE' | translate) + (isRequired? ' *': '')" [required]="isRequired" [disabled]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('type').disabled">
<mat-select class="col-md-12" [formControl]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('type')" [placeholder]="('TYPES.DATASET-PROFILE-IDENTIFIER.IDENTIFIER-TYPE' | translate) + (isRequired? ' *': '')" [disabled]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('type').disabled">
<mat-option *ngFor="let type of datasetIdTypes" [value]="type.value">
{{ type.name }}
</mat-option>
@ -206,7 +206,7 @@
<div class="row align-items-baseline">
<mat-form-field class="col-md-4">
<mat-label>{{ field.data.label }}</mat-label>
<input matInput class="col-md-12" [formControl]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier')" placeholder="{{(field.data.label) + (isRequired? ' *': '')}}" [required]="isRequired">
<input matInput class="col-md-12" [formControl]="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier')" placeholder="{{(field.data.label) + (isRequired? ' *': '')}}" >
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').hasError('backendError')">{{propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').getError('backendError').message}}</mat-error>
<mat-error *ngIf="propertiesFormGroup?.get(field.id).get('externalIdentifier')?.get('identifier').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field>

View File

@ -80,11 +80,12 @@ export class FormProgressIndicationComponent extends BaseComponent implements On
countRequiredFieldsByFieldset(ordinal: number, fieldsFormGroup: UntypedFormGroup, filterValid: boolean = false): number {
let fieldsCount: number = 0;
const fieldNames = Object.keys(fieldsFormGroup.controls);
for(let item of fieldNames) {
const fieldSetNames = Object.keys(fieldsFormGroup.controls);
for(let item of fieldSetNames) {
if (!this.checkVisibility || this.visibilityRulesService.isVisible(item, ordinal)) {
const fieldControl = fieldsFormGroup.get(item);
for (let fieldType of this.fieldTypes) {
const fieldNames = Object.keys((fieldControl as UntypedFormGroup).controls);
for (let fieldType of fieldNames) {
const typedControl = fieldControl.get(fieldType);
let controlFilter: boolean = this.controlRequired(typedControl) && this.controlEnabled(typedControl);
if (filterValid) controlFilter = controlFilter && typedControl.valid;

View File

@ -4,7 +4,6 @@
<div *ngIf="showItem(groupMenuItem);">
<hr *ngIf="!firstGroup">
<mat-list-item routerLinkActive="active" [isActiveMatchOptions]="{ paths: 'exact', queryParams: 'ignored' }" *ngFor="let groupMenuRoute of groupMenuItem.routes; let first = first" class="nav-item" [ngClass]="{'mt-4': first && firstGroup}">
<!-- {{ groupMenuRoute |json }} -->
<a class="new-dmp nav-link nav-row" *ngIf="groupMenuRoute.path !== '/contact-support' && groupMenuRoute.path !== '/co-branding' && groupMenuRoute.path !== '/feedback' && groupMenuRoute.path !== '/descriptions'" [routerLink]="[groupMenuRoute.path]" [ngClass]="{'dmp-tour': groupMenuRoute.path == '/plans'}">
<i class="material-symbols-outlined icon">{{ groupMenuRoute.icon }}</i>
<i *ngIf="groupMenuRoute.path == '/plans'" class="material-symbols-outlined icon-mask">person</i>

View File

@ -1,5 +1,3 @@
<!-- {{ userCredentials | async | json }} -->
<div class="profile">
<div class="container-fluid">
<div *ngIf="user | async as userProfile; else loading" class="user-profile">

View File

@ -2,6 +2,7 @@ import { AbstractControl, UntypedFormArray, UntypedFormGroup, ValidatorFn, Valid
import { ValidationErrorModel } from '@common/forms/validation/error-model/validation-error-model';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { DmpBlueprintSystemFieldType } from '@app/core/common/enum/dmp-blueprint-system-field-type';
import { VisibilityRulesService } from '@app/ui/description/editor/description-form/visibility-rules/visibility-rules.service';
export function BackendErrorValidator(errorModel: ValidationErrorModel, propertyName: string): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
@ -29,6 +30,17 @@ export function CustomErrorValidator(errorModel: ValidationErrorModel, propertyN
};
}
export function RequiredWithVisibilityRulesValidator(visibilityRulesService: VisibilityRulesService, visibilityRulesKey: string) {
return (control: AbstractControl): { [key: string]: any } => {
if(visibilityRulesService.isVisibleMap[visibilityRulesKey] ?? true) {
return Validators.required(control);
}
control.setErrors(null);
return null;
};
}
export function DateValidator(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
if (control.value) {
@ -108,20 +120,20 @@ export function DmpBlueprintSystemFieldRequiredValidator(): ValidatorFn {
let foundAccess = false;
const sectionsFormArray = (control as UntypedFormArray);
if (sectionsFormArray.controls != null && sectionsFormArray.controls.length > 0 ){
if (sectionsFormArray.controls != null && sectionsFormArray.controls.length > 0) {
sectionsFormArray.controls.forEach((section, index) => {
const fieldsFormArray = section.get('fields') as UntypedFormArray;
if (fieldsFormArray && fieldsFormArray.length > 0){
if (fieldsFormArray.controls.some(y => (y as UntypedFormGroup).get('systemFieldType')?.value === DmpBlueprintSystemFieldType.Title)){
if (fieldsFormArray && fieldsFormArray.length > 0) {
if (fieldsFormArray.controls.some(y => (y as UntypedFormGroup).get('systemFieldType')?.value === DmpBlueprintSystemFieldType.Title)) {
foundTitle = true;
}
if (fieldsFormArray.controls.some(y => (y as UntypedFormGroup).get('systemFieldType')?.value === DmpBlueprintSystemFieldType.Description)){
if (fieldsFormArray.controls.some(y => (y as UntypedFormGroup).get('systemFieldType')?.value === DmpBlueprintSystemFieldType.Description)) {
foundDescription = true;
}
if (fieldsFormArray.controls.some(y => (y as UntypedFormGroup).get('systemFieldType')?.value === DmpBlueprintSystemFieldType.Language)){
if (fieldsFormArray.controls.some(y => (y as UntypedFormGroup).get('systemFieldType')?.value === DmpBlueprintSystemFieldType.Language)) {
foundLanguage = true;
}
if (fieldsFormArray.controls.some(y => (y as UntypedFormGroup).get('systemFieldType')?.value === DmpBlueprintSystemFieldType.AccessRights)){
if (fieldsFormArray.controls.some(y => (y as UntypedFormGroup).get('systemFieldType')?.value === DmpBlueprintSystemFieldType.AccessRights)) {
foundAccess = true;
}
}