fix dmp blueprint editor validators

This commit is contained in:
amentis 2024-01-18 11:59:42 +02:00
parent 17dc3e47f1
commit ace6ce1119
3 changed files with 181 additions and 27 deletions

View File

@ -39,8 +39,8 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.NAME' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.NAME' | translate}}</mat-label>
<input matInput type="text" name="label" [formControl]="formGroup.get('label')" required> <input matInput type="text" name="label" [formControl]="formGroup.get('label')" required>
<mat-error *ngIf="formGroup.get('label').hasError('required')"> <mat-error *ngIf="formGroup.get('label').hasError('backendError')">{{formGroup.get('label').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="formGroup.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<h4 class="col-12">{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTIONS' | translate}}</h4> <h4 class="col-12">{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTIONS' | translate}}</h4>
@ -69,16 +69,16 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTION-NAME' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTION-NAME' | translate}}</mat-label>
<input matInput type="text" name="label" [formControl]="section.get('label')" required> <input matInput type="text" name="label" [formControl]="section.get('label')" required>
<mat-error *ngIf="section.get('label').hasError('required')"> <mat-error *ngIf="section.get('label').hasError('backendError')">{{section.get('label').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="section.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTION-DESCRIPTION' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.SECTION-DESCRIPTION' | translate}}</mat-label>
<input matInput type="text" name="description" [formControl]="section.get('description')"> <input matInput type="text" name="description" [formControl]="section.get('description')">
<mat-error *ngIf="section.get('description').hasError('required')"> <mat-error *ngIf="section.get('description').hasError('backendError')">{{section.get('description').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="section.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-6"> <div class="col-6">
@ -119,32 +119,35 @@
{{enumUtils.toDmpBlueprintExtraFieldDataTypeString(extraFieldDataType)}} {{enumUtils.toDmpBlueprintExtraFieldDataTypeString(extraFieldDataType)}}
</mat-option> </mat-option>
</mat-select> </mat-select>
<mat-error *ngIf="field.get('dataType').hasError('required')"> <mat-error *ngIf="field.get('dataType').hasError('backendError')">{{field.get('dataType').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="field.get('dataType').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col"> <div class="col">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-LABEL' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-LABEL' | translate}}</mat-label>
<input matInput type="text" name="label" [formControl]="field.get('label')" required> <input matInput type="text" name="label" [formControl]="field.get('label')" required>
<mat-error *ngIf="field.get('label').hasError('required')"> <mat-error *ngIf="field.get('label').hasError('backendError')">{{field.get('label').getError('backendError').message}}</mat-error>
{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error> <mat-error *ngIf="field.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col"> <div class="col">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-PLACEHOLDER' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-PLACEHOLDER' | translate}}</mat-label>
<input matInput type="text" name="placeholder" [formControl]="field.get('placeholder')"> <input matInput type="text" name="placeholder" [formControl]="field.get('placeholder')">
<mat-error *ngIf="field.get('placeholder').hasError('backendError')">{{field.get('placeholder').getError('backendError').message}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col"> <div class="col">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-DESCRIPTION' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-DESCRIPTION' | translate}}</mat-label>
<input matInput type="text" name="description" [formControl]="field.get('description')"> <input matInput type="text" name="description" [formControl]="field.get('description')">
<mat-error *ngIf="field.get('description').hasError('backendError')">{{field.get('description').getError('backendError').message}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-auto"> <div class="col-auto">
<mat-checkbox [disabled]="field.get('systemFieldType')?.value === dmpBlueprintSystemFieldType.TEXT || field.get('systemFieldType')?.value === dmpBlueprintSystemFieldType.HTML_TEXT" [formControl]="field.get('required')"><span>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-REQUIRED' | translate}}</span></mat-checkbox> <mat-checkbox [disabled]="field.get('systemFieldType')?.value === dmpBlueprintSystemFieldType.TEXT || field.get('systemFieldType')?.value === dmpBlueprintSystemFieldType.HTML_TEXT" [formControl]="field.get('required')"><span>{{'DMP-BLUEPRINT-EDITOR.FIELDS.FIELD-REQUIRED' | translate}}</span></mat-checkbox>
<mat-error *ngIf="field.get('systemFieldType').hasError('backendError')">{{field.get('systemFieldType').getError('backendError').message}}</mat-error>
</div> </div>
<div *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM" [hidden]="viewOnly" class="col-auto"> <div *ngIf="field.get('category').value === dmpBlueprintSectionFieldCategory.SYSTEM" [hidden]="viewOnly" class="col-auto">
<button mat-icon-button matTooltip="{{'DMP-BLUEPRINT-EDITOR.ACTIONS.REMOVE-SYSTEM-FIELD' | translate}}" (click)="removeSystemField(sectionIndex, fieldIndex)" [disabled]="formGroup.disabled"> <button mat-icon-button matTooltip="{{'DMP-BLUEPRINT-EDITOR.ACTIONS.REMOVE-SYSTEM-FIELD' | translate}}" (click)="removeSystemField(sectionIndex, fieldIndex)" [disabled]="formGroup.disabled">
@ -164,7 +167,8 @@
<div class="col-12"> <div class="col-12">
<div class="row"> <div class="row">
<div class="col-auto"> <div class="col-auto">
<mat-checkbox [formControl]="section.get('hasTemplates')" (change)="checkForBlueprints($event, sectionIndex)"> <!-- <mat-checkbox [formControl]="section.get('hasTemplates')" (change)="checkForBlueprints($event, sectionIndex)"> -->
<mat-checkbox [formControl]="section.get('hasTemplates')">
{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}} {{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATES' | translate}}
</mat-checkbox> </mat-checkbox>
</div> </div>
@ -189,18 +193,21 @@
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-LABEL' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-LABEL' | translate}}</mat-label>
<input matInput type="text" value="descriptionTemplate.get('label')" name="label" [formControl]="descriptionTemplate.get('label')"> <input matInput type="text" value="descriptionTemplate.get('label')" name="label" [formControl]="descriptionTemplate.get('label')">
<mat-error *ngIf="descriptionTemplate.get('label').hasError('backendError')">{{descriptionTemplate.get('label').getError('backendError').message}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-4"> <div class="col-4">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MIN-MULTIPLICITY' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MIN-MULTIPLICITY' | translate}}</mat-label>
<input matInput type="number" min="0" name="minMultiplicity" [formControl]="descriptionTemplate.get('minMultiplicity')"> <input matInput type="number" min="0" name="minMultiplicity" [formControl]="descriptionTemplate.get('minMultiplicity')">
<mat-error *ngIf="descriptionTemplate.get('minMultiplicity').hasError('backendError')">{{descriptionTemplate.get('minMultiplicity').getError('backendError').message}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="col-4"> <div class="col-4">
<mat-form-field class="w-100"> <mat-form-field class="w-100">
<mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MAX-MULTIPLICITY' | translate}}</mat-label> <mat-label>{{'DMP-BLUEPRINT-EDITOR.FIELDS.DESCRIPTION-TEMPLATE-MAX-MULTIPLICITY' | translate}}</mat-label>
<input matInput type="number" min="1" name="maxMultiplicity" [formControl]="descriptionTemplate.get('maxMultiplicity')"> <input matInput type="number" min="1" name="maxMultiplicity" [formControl]="descriptionTemplate.get('maxMultiplicity')">
<mat-error *ngIf="descriptionTemplate.get('maxMultiplicity').hasError('backendError')">{{descriptionTemplate.get('maxMultiplicity').getError('backendError').message}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>

View File

@ -214,11 +214,7 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
// //
// //
addSection(): void { addSection(): void {
const section: DmpBlueprintDefinitionSectionEditorModel = new DmpBlueprintDefinitionSectionEditorModel(); (this.formGroup.get('definition').get('sections') as FormArray).push(this.editorModel.createChildSection( (this.formGroup.get('definition').get('sections') as FormArray).controls.length));
section.id = Guid.create();
section.ordinal = (this.formGroup.get('definition').get('sections') as FormArray).controls.length + 1;
section.hasTemplates = false;
(this.formGroup.get('definition').get('sections') as FormArray).push(section.buildForm()); //TODO: dtziotzios validation path
} }
removeSection(sectionIndex: number): void { removeSection(sectionIndex: number): void {
@ -226,6 +222,16 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
(this.formGroup.get('definition').get('sections') as FormArray).controls.forEach((section, index) => { (this.formGroup.get('definition').get('sections') as FormArray).controls.forEach((section, index) => {
section.get('ordinal').setValue(index + 1); section.get('ordinal').setValue(index + 1);
}); });
//Reapply validators
DmpBlueprintEditorModel.reApplySectionValidators(
{
formGroup: this.formGroup,
validationErrorModel: this.editorModel.validationErrorModel
}
);
this.formGroup.get('definition').get('sections').markAsDirty();
} }
dropSections(event: CdkDragDrop<string[]>) { dropSections(event: CdkDragDrop<string[]>) {
@ -282,11 +288,9 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
} }
addExtraField(sectionIndex: number): void { addExtraField(sectionIndex: number): void {
const field: FieldInSectionEditorModel = new FieldInSectionEditorModel(); ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray)
field.id = Guid.create(); .push(this.editorModel.createChildExtraField(sectionIndex, ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).length));
field.ordinal = ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).length + 1;
field.category = DmpBlueprintSectionFieldCategory.EXTRA;
((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).push(field.buildForm()); //TODO: dtziotzios validation path
} }
removeExtraField(sectionIndex: number, fieldIndex: number): void { removeExtraField(sectionIndex: number, fieldIndex: number): void {
@ -295,6 +299,16 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
formArray.controls.forEach((section, index) => { formArray.controls.forEach((section, index) => {
section.get('ordinal').setValue(index + 1); section.get('ordinal').setValue(index + 1);
}); });
//Reapply validators
DmpBlueprintEditorModel.reApplySectionValidators(
{
formGroup: this.formGroup,
validationErrorModel: this.editorModel.validationErrorModel
}
);
(this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields').markAsDirty();
// ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('fields') as FormArray).at(fieldIndex).markAsDirty();
} }
@ -328,15 +342,20 @@ export class DmpBlueprintEditorComponent extends BaseEditor<DmpBlueprintEditorMo
const foundIndex = descriptionTemplateFormArray.controls.findIndex(blueprint => blueprint.get('descriptionTemplateId').value === event.id); const foundIndex = descriptionTemplateFormArray.controls.findIndex(blueprint => blueprint.get('descriptionTemplateId').value === event.id);
if (foundIndex !== -1) { if (foundIndex !== -1) {
descriptionTemplateFormArray.removeAt(foundIndex); descriptionTemplateFormArray.removeAt(foundIndex);
DmpBlueprintEditorModel.reApplySectionValidators(
{
formGroup: this.formGroup,
validationErrorModel: this.editorModel.validationErrorModel
}
)
this.formGroup.get('definition').get('sections').markAsDirty();
} }
} }
onSelectDescritionTemplate(item, sectionIndex) { onSelectDescritionTemplate(item, sectionIndex) {
const descriptionTemplate: DescriptionTemplatesInSectionEditorModel = new DescriptionTemplatesInSectionEditorModel(); ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray)
descriptionTemplate.id = Guid.create(); .push(this.editorModel.createChildDescriptionTemplate(item, sectionIndex, ((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray).length));
descriptionTemplate.descriptionTemplateId = item.id;
descriptionTemplate.label = item.label;
((this.formGroup.get('definition').get('sections') as FormArray).at(sectionIndex).get('descriptionTemplates') as FormArray).push(descriptionTemplate.buildForm()); //TODO: dtziotzios validation path
} }
// ngAfterViewInit() { // ngAfterViewInit() {

View File

@ -1,4 +1,4 @@
import { UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms"; import { FormArray, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators } from "@angular/forms";
import { DmpBlueprintExtraFieldDataType } from "@app/core/common/enum/dmp-blueprint-field-type"; import { DmpBlueprintExtraFieldDataType } from "@app/core/common/enum/dmp-blueprint-field-type";
import { DmpBlueprintSectionFieldCategory } from "@app/core/common/enum/dmp-blueprint-section-field-category"; import { DmpBlueprintSectionFieldCategory } from "@app/core/common/enum/dmp-blueprint-section-field-category";
import { DmpBlueprintStatus } from "@app/core/common/enum/dmp-blueprint-status"; import { DmpBlueprintStatus } from "@app/core/common/enum/dmp-blueprint-status";
@ -58,6 +58,44 @@ export class DmpBlueprintEditorModel extends BaseEditorModel implements DmpBluep
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
} }
createChildSection(index: number): UntypedFormGroup {
const section: DmpBlueprintDefinitionSectionEditorModel = new DmpBlueprintDefinitionSectionEditorModel(this.validationErrorModel);
section.id = Guid.create();
section.ordinal = index + 1;
section.hasTemplates = false;
return section.buildForm({ rootPath: 'definition.sections[' + index + '].' });
}
createChildExtraField(sectionIndex: number, index: number): UntypedFormGroup {
const field: FieldInSectionEditorModel = new FieldInSectionEditorModel(this.validationErrorModel);
field.id = Guid.create();
field.ordinal = index + 1;
field.category = DmpBlueprintSectionFieldCategory.EXTRA;
return field.buildForm({ rootPath: 'definition.sections[' + sectionIndex + '].fields[' + index + '].'});
}
createChildDescriptionTemplate(item: any, sectionIndex: number, index: number): UntypedFormGroup {
const descriptionTemplate: DescriptionTemplatesInSectionEditorModel = new DescriptionTemplatesInSectionEditorModel(this.validationErrorModel);
descriptionTemplate.id = Guid.create();
descriptionTemplate.descriptionTemplateId = item.id;
descriptionTemplate.label = item.label;
return descriptionTemplate.buildForm({ rootPath: 'definition.sections[' + sectionIndex + '].descriptionTemplates[' + index + '].'});
}
static reApplySectionValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
}): void {
const { formGroup, validationErrorModel } = params;
const control = formGroup?.get('definition');
DmpBlueprintDefinitionEditorModel.reapplySectionsValidators({
formArray: control.get('sections') as UntypedFormArray,
rootPath: `definition.`,
validationErrorModel: validationErrorModel
});
}
} }
export class DmpBlueprintDefinitionEditorModel implements DmpBlueprintDefinitionPersist { export class DmpBlueprintDefinitionEditorModel implements DmpBlueprintDefinitionPersist {
@ -115,6 +153,21 @@ export class DmpBlueprintDefinitionEditorModel implements DmpBlueprintDefinition
return baseContext; return baseContext;
} }
static reapplySectionsValidators(params: {
formArray: UntypedFormArray,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const { validationErrorModel, rootPath, formArray } = params;
formArray?.controls?.forEach(
(control, index) => DmpBlueprintDefinitionSectionEditorModel.reapplySectionValidators({
formGroup: control as UntypedFormGroup,
rootPath: `${rootPath}sections[${index}].`,
validationErrorModel: validationErrorModel
})
);
}
} }
export class DmpBlueprintDefinitionSectionEditorModel implements DmpBlueprintDefinitionSectionPersist { export class DmpBlueprintDefinitionSectionEditorModel implements DmpBlueprintDefinitionSectionPersist {
@ -206,6 +259,43 @@ export class DmpBlueprintDefinitionSectionEditorModel implements DmpBlueprintDef
return baseContext; return baseContext;
} }
static reapplySectionValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
const context = DmpBlueprintDefinitionSectionEditorModel.createValidationContext({
rootPath,
validationErrorModel
});
['id','label', 'ordinal', 'description', 'hasTemplates', 'hash'].forEach(keyField => {
const control = formGroup?.get(keyField);
control?.clearValidators();
control?.addValidators(context.getValidation(keyField).validators);
});
(formGroup.get('fields') as FormArray).controls?.forEach(
(control, index) => FieldInSectionEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `${rootPath}fields[${index}].`,
validationErrorModel: validationErrorModel
}
)
);
(formGroup.get('fields') as FormArray).controls?.forEach(
(control, index) => DescriptionTemplatesInSectionEditorModel.reapplyValidators({
formGroup: control as UntypedFormGroup,
rootPath: `${rootPath}descriptionTemplates[${index}].`,
validationErrorModel: validationErrorModel
}
)
);
}
} }
export class FieldInSectionEditorModel implements FieldInSectionPersist { export class FieldInSectionEditorModel implements FieldInSectionPersist {
@ -288,6 +378,25 @@ export class FieldInSectionEditorModel implements FieldInSectionPersist {
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
} }
static reapplyValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
const context = FieldInSectionEditorModel.createValidationContext({
rootPath,
validationErrorModel
});
['id', 'category', 'dataType', 'systemFieldType', 'label', 'placeholder', 'description', 'required', 'ordinal'].forEach(keyField => {
const control = formGroup?.get(keyField);
control?.clearValidators();
control?.addValidators(context.getValidation(keyField).validators);
})
}
} }
export class DescriptionTemplatesInSectionEditorModel implements DescriptionTemplatesInSectionPersist { export class DescriptionTemplatesInSectionEditorModel implements DescriptionTemplatesInSectionPersist {
@ -352,4 +461,23 @@ export class DescriptionTemplatesInSectionEditorModel implements DescriptionTemp
baseContext.validation = baseValidationArray; baseContext.validation = baseValidationArray;
return baseContext; return baseContext;
} }
static reapplyValidators(params: {
formGroup: UntypedFormGroup,
validationErrorModel: ValidationErrorModel,
rootPath: string
}): void {
const { formGroup, rootPath, validationErrorModel } = params;
const context = DescriptionTemplatesInSectionEditorModel.createValidationContext({
rootPath,
validationErrorModel
});
['id', 'descriptionTemplateId', 'label', 'minMultiplicity', 'maxMultiplicity'].forEach(keyField => {
const control = formGroup?.get(keyField);
control?.clearValidators();
control?.addValidators(context.getValidation(keyField).validators);
})
}
} }