Dataset ProfileEditor Validator fixes. More validators added. Table of contents mark invalid entries. Guided tour fix. Fix ng-deep leaks from user listing.

This commit is contained in:
Kristian Ntavidi 2021-03-12 18:19:51 +02:00
parent 615d30b977
commit 4d6e4fb2cd
18 changed files with 418 additions and 192 deletions

View File

@ -64,12 +64,31 @@ export class AppComponent implements OnInit, AfterViewInit {
ngAfterViewInit(): void { ngAfterViewInit(): void {
setTimeout(() => { setTimeout(() => {
this.sideNavSubscription = this.sidenavService.status().subscribe(isopen=>{ this.sideNavSubscription = this.sidenavService.status().subscribe(isopen=>{
const hamburger = document.getElementById('hamburger');
if(isopen){ if(isopen){
//update value of hamburfer //update value of hamburfer
document.getElementById('hamburger').classList.add('change'); if(!hamburger){//try later
setTimeout(() => {
const hamburger = document.getElementById('hamburger');
if(hamburger){
hamburger.classList.add('change');
}
}, 300);
}else{
hamburger.classList.add('change');
}
this.sidenav.open() this.sidenav.open()
}else{ }else{//closed
document.getElementById('hamburger').classList.remove('change'); if(!hamburger){//try later
setTimeout(() => {
const hamburger = document.getElementById('hamburger');
if(hamburger){
hamburger.classList.remove('change');
}
}, 300);
}else{
hamburger.classList.remove('change');
}
this.sidenav.close(); this.sidenav.close();
} }

View File

@ -388,7 +388,10 @@ export class GuidedTourComponent implements AfterViewInit, OnDestroy {
} }
const scrollAdjustment = this.currentTourStep.scrollAdjustment ? this.currentTourStep.scrollAdjustment : 0; const scrollAdjustment = this.currentTourStep.scrollAdjustment ? this.currentTourStep.scrollAdjustment : 0;
const tourStepHeight = typeof this.tourStep.nativeElement.getBoundingClientRect === 'function' ? this.tourStep.nativeElement.getBoundingClientRect().height : 0; let tourStepHeight = 0;
if (this.tourStep != null && this.tourStep.nativeElement != null && typeof this.tourStep.nativeElement.getBoundingClientRect === 'function') {
tourStepHeight = this.tourStep.nativeElement.getBoundingClientRect().height;
}
const elementHeight = this.selectedElementRect.height + scrollAdjustment + tourStepHeight; const elementHeight = this.selectedElementRect.height + scrollAdjustment + tourStepHeight;
if ((this.windowRef.nativeWindow.innerHeight - this.topOfPageAdjustment) < elementHeight) { if ((this.windowRef.nativeWindow.innerHeight - this.topOfPageAdjustment) < elementHeight) {

View File

@ -67,12 +67,12 @@
</div> </div>
</div> --> </div> -->
<mat-form-field appearance="none" class="numbering-label" [ngStyle]="calculateLabelWidth(numbering)"> <mat-form-field appearance="none" class="numbering-label" [ngStyle]="calculateLabelWidth(numbering)">
<input matInput type="text" [value]="numbering" disabled> <input [ngClass]="{'text-danger':form.get('title').invalid &&form.get('title').touched}" matInput type="text" [value]="numbering" disabled>
</mat-form-field> </mat-form-field>
<!-- [appearance]="titleControl.focused? 'legacy':'none'" floatLabel="never" --> <!-- [appearance]="titleControl.focused? 'legacy':'none'" floatLabel="never" -->
<mat-form-field class="col field-title" [appearance]="'none'"> <mat-form-field class="col field-title" [appearance]="'none'" floatLabel="never">
<input matInput type="text" placeholder="Title" #titleControl="matInput" <input matInput type="text" placeholder="Title" #titleControl="matInput"
[formControl]="this.form.get('title')"> [formControl]="this.form.get('title')" required>
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
@ -145,6 +145,7 @@
[form]="form.get('fields').get(''+i)" [showOrdinal]="false" [form]="form.get('fields').get(''+i)" [showOrdinal]="false"
[indexPath]="indexPath + 'f' + i" [viewOnly]="viewOnly" [indexPath]="indexPath + 'f' + i" [viewOnly]="viewOnly"
[expandView]="hasFocus" [expandView]="hasFocus"
[canBeDeleted]="form.get('fields')['controls'].length !=1"
(delete)="deleteField(i)"> (delete)="deleteField(i)">
</app-dataset-profile-editor-field-component> </app-dataset-profile-editor-field-component>
</div> </div>

View File

@ -32,6 +32,7 @@ import { CurrencyDataEditorModel } from '../../../admin/field-data/currency-data
import { ValidationDataEditorModel } from '../../../admin/field-data/validation-data-editor-models'; import { ValidationDataEditorModel } from '../../../admin/field-data/validation-data-editor-models';
import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service'; import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service';
import { OrganizationsDataEditorModel } from '../../../admin/field-data/organizations-data-editor-models'; import { OrganizationsDataEditorModel } from '../../../admin/field-data/organizations-data-editor-models';
import { EditorCustomValidators } from '../../custom-validators/editor-custom-validators';
@Component({ @Component({
selector: 'app-dataset-profile-editor-composite-field-component', selector: 'app-dataset-profile-editor-composite-field-component',
@ -59,6 +60,7 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh
viewStyleEnum = DatasetProfileFieldViewStyle; viewStyleEnum = DatasetProfileFieldViewStyle;
viewTypeEnum = ViewStyleType; viewTypeEnum = ViewStyleType;
private myCustomValidators:EditorCustomValidators = new EditorCustomValidators();
constructor( constructor(
private dialog: MatDialog, private dialog: MatDialog,
@ -358,15 +360,15 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh
fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox) fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox)
fieldForm.addControl('data', new WordListFieldDataEditorModel().buildForm()); fieldForm.addControl('data', new WordListFieldDataEditorModel().buildForm());
this.form.get('data').setValidators(this._atLeastOneElementListValidator('options')); fieldForm.get('data').setValidators(this.myCustomValidators.atLeastOneElementListValidator('options'));
this.form.get('data').updateValueAndValidity(); fieldForm.get('data').updateValueAndValidity();
break; break;
case this.viewTypeEnum.Other: case this.viewTypeEnum.Other:
fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox) fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox)
fieldForm.addControl('data', new AutoCompleteFieldDataEditorModel().buildForm()); //TODO SEE fieldForm.addControl('data', new AutoCompleteFieldDataEditorModel().buildForm()); //TODO SEE
fieldForm.get('data').setValidators(this._atLeastOneElementListValidator('autoCompleteSingleDataList')); fieldForm.get('data').setValidators(this.myCustomValidators.atLeastOneElementListValidator('autoCompleteSingleDataList'));
fieldForm.get('data').updateValueAndValidity();
break; break;
case this.viewTypeEnum.InternalDmpEntities: case this.viewTypeEnum.InternalDmpEntities:
@ -380,6 +382,9 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh
case this.viewTypeEnum.RadioBox: case this.viewTypeEnum.RadioBox:
fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.RadioBox) fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.RadioBox)
fieldForm.addControl('data', new RadioBoxFieldDataEditorModel().buildForm()); fieldForm.addControl('data', new RadioBoxFieldDataEditorModel().buildForm());
fieldForm.get('data').setValidators(this.myCustomValidators.atLeastOneElementListValidator('options'));
fieldForm.get('data').updateValueAndValidity();
break; break;
case this.viewTypeEnum.TextArea: case this.viewTypeEnum.TextArea:
fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.TextArea) fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.TextArea)
@ -416,7 +421,7 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh
break; break;
case this.viewTypeEnum.Organizations: case this.viewTypeEnum.Organizations:
fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Organizations) fieldForm.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.Organizations)
this.form.addControl('data', new OrganizationsDataEditorModel().buildForm()); fieldForm.addControl('data', new OrganizationsDataEditorModel().buildForm());
// this.form.addControl('data', new OrganizationsDataEditorModel().buildForm()) // this.form.addControl('data', new OrganizationsDataEditorModel().buildForm())
// fieldForm.addControl('data', new DatasetsAutoCompleteFieldDataEditorModel().buildForm()); //TODO // fieldForm.addControl('data', new DatasetsAutoCompleteFieldDataEditorModel().buildForm()); //TODO
break; break;
@ -436,7 +441,9 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh
(<FormArray>this.form.get('fields')).push(fieldForm); (<FormArray>this.form.get('fields')).push(fieldForm);
// fieldForm.updateValueAndValidity(); fieldForm.get('viewStyle').get('renderStyle').updateValueAndValidity();
fieldForm.get('data').updateValueAndValidity();
} }
@ -488,17 +495,17 @@ export class DatasetProfileEditorCompositeFieldComponent implements OnInit, OnCh
// } // }
private _atLeastOneElementListValidator(arrayToCheck): ValidatorFn{ // private _atLeastOneElementListValidator(arrayToCheck): ValidatorFn{
return (control: AbstractControl): ValidationErrors | null=>{ // return (control: AbstractControl): ValidationErrors | null=>{
const fa = control.get(arrayToCheck) as FormArray; // const fa = control.get(arrayToCheck) as FormArray;
if(fa.length === 0){ // if(fa.length === 0){
return {emptyArray: true}; // return {emptyArray: true};
} // }
return null; // return null;
} // }
} // }
calculateLabelWidth(numbering: string){ calculateLabelWidth(numbering: string){

View File

@ -12,7 +12,7 @@
<li class="list-inline-item" *ngIf="!viewOnly && viewType"> <li class="list-inline-item" *ngIf="!viewOnly && viewType">
<mat-icon style="cursor: pointer;" (click)="addNewRule()" [matTooltip]="'DATASET-PROFILE-EDITOR.ACTIONS.FIELD.ADD-VISIBILITY-RULE' | translate">visibility</mat-icon> <mat-icon style="cursor: pointer;" (click)="addNewRule()" [matTooltip]="'DATASET-PROFILE-EDITOR.ACTIONS.FIELD.ADD-VISIBILITY-RULE' | translate">visibility</mat-icon>
</li> </li>
<li class="list-inline-item" *ngIf="!viewOnly && viewType"> <li class="list-inline-item" *ngIf="!viewOnly && viewType && canBeDeleted">
<mat-icon style="cursor: pointer;" (click)="onDelete()" [matTooltip]="'DATASET-PROFILE-EDITOR.ACTIONS.FIELD.DELETE-INPUT' | translate">delete</mat-icon> <mat-icon style="cursor: pointer;" (click)="onDelete()" [matTooltip]="'DATASET-PROFILE-EDITOR.ACTIONS.FIELD.DELETE-INPUT' | translate">delete</mat-icon>
</li> </li>

View File

@ -60,7 +60,7 @@ export class DatasetProfileEditorFieldComponent extends BaseComponent implements
@Input() expandView: boolean = true; @Input() expandView: boolean = true;
@Input() canBeDeleted:boolean = true;
@Output() delete = new EventEmitter<void>(); @Output() delete = new EventEmitter<void>();
@ -425,7 +425,7 @@ export class DatasetProfileEditorFieldComponent extends BaseComponent implements
this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox) this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox)
this.form.addControl('data', new WordListFieldDataEditorModel().buildForm()); this.form.addControl('data', new WordListFieldDataEditorModel().buildForm());
this.form.get('data').setValidators(this.myCustomValidators._atLeastOneElementListValidator('options')); this.form.get('data').setValidators(this.myCustomValidators.atLeastOneElementListValidator('options'));
this.form.get('data').updateValueAndValidity(); this.form.get('data').updateValueAndValidity();
break; break;
@ -433,7 +433,7 @@ export class DatasetProfileEditorFieldComponent extends BaseComponent implements
this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox) this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.ComboBox)
this.form.addControl('data', new AutoCompleteFieldDataEditorModel().buildForm()); //TODO SEE this.form.addControl('data', new AutoCompleteFieldDataEditorModel().buildForm()); //TODO SEE
this.form.get('data').setValidators(this.myCustomValidators._atLeastOneElementListValidator('autoCompleteSingleDataList')); this.form.get('data').setValidators(this.myCustomValidators.atLeastOneElementListValidator('autoCompleteSingleDataList'));
this.form.get('data').updateValueAndValidity(); this.form.get('data').updateValueAndValidity();
@ -450,7 +450,7 @@ export class DatasetProfileEditorFieldComponent extends BaseComponent implements
this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.RadioBox) this.form.get('viewStyle').get('renderStyle').setValue(DatasetProfileFieldViewStyle.RadioBox)
this.form.addControl('data', new RadioBoxFieldDataEditorModel().buildForm()); this.form.addControl('data', new RadioBoxFieldDataEditorModel().buildForm());
this.form.get('data').setValidators(this.myCustomValidators._atLeastOneElementListValidator('options')); this.form.get('data').setValidators(this.myCustomValidators.atLeastOneElementListValidator('options'));
this.form.get('data').updateValueAndValidity(); this.form.get('data').updateValueAndValidity();
break; break;
@ -504,6 +504,10 @@ export class DatasetProfileEditorFieldComponent extends BaseComponent implements
this.form.addControl('data', new ValidationDataEditorModel().buildForm()); this.form.addControl('data', new ValidationDataEditorModel().buildForm());
break; break;
} }
this.form.get('data').updateValueAndValidity();
this.form.get('viewStyle').get('renderStyle').updateValueAndValidity();
this.form.updateValueAndValidity();
setTimeout(() => { //TODO setTimeout(() => { //TODO
this.showPreview = true; this.showPreview = true;
}); });

View File

@ -130,6 +130,8 @@ export class DatasetProfileEditorSectionFieldSetComponent extends BaseComponent
if(el){ if(el){
el.scrollIntoView({behavior: "smooth"}); el.scrollIntoView({behavior: "smooth"});
} }
}else{//scroll on top
window.scrollTo({top:0, behavior:'smooth'});
} }
} }

View File

@ -13,7 +13,8 @@
<div class="hint col-12">{{'DATASET-PROFILE-EDITOR.STEPS.SECTION-INFO.SECTION-NAME-HINT' | translate}}</div> <div class="hint col-12">{{'DATASET-PROFILE-EDITOR.STEPS.SECTION-INFO.SECTION-NAME-HINT' | translate}}</div>
<mat-form-field class="col-12"> <mat-form-field class="col-12">
<input matInput type="text" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.SECTION.FIELDS.TITLE' | translate}}" <input matInput type="text" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.SECTION.FIELDS.TITLE' | translate}}"
formControlName="title"> formControlName="title" required>
<mat-error >{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
<!-- <mat-form-field class="col-md-3"> <!-- <mat-form-field class="col-md-3">
<mat-select placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.SECTION.FIELDS.PAGE' | translate}}" formControlName="page" <mat-select placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.SECTION.FIELDS.PAGE' | translate}}" formControlName="page"
@ -30,7 +31,8 @@
<div class="hint col-12">{{'DATASET-PROFILE-EDITOR.STEPS.SECTION-INFO.SECTION-DESCRIPTION-HINT' | translate}}</div> <div class="hint col-12">{{'DATASET-PROFILE-EDITOR.STEPS.SECTION-INFO.SECTION-DESCRIPTION-HINT' | translate}}</div>
<mat-form-field class="col-12"> <mat-form-field class="col-12">
<input matInput type="text" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.SECTION.FIELDS.DESCRIPTION' | translate}}" <input matInput type="text" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.SECTION.FIELDS.DESCRIPTION' | translate}}"
formControlName="description"> formControlName="description" required>
<mat-error >{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>

View File

@ -4,16 +4,64 @@ import { AbstractControl, FormArray, ValidationErrors, ValidatorFn } from "@angu
export class EditorCustomValidators{ export class EditorCustomValidators{
public _atLeastOneElementListValidator(arrayToCheck): ValidatorFn{ public atLeastOneElementListValidator(arrayToCheck): ValidatorFn{
return (control: AbstractControl): ValidationErrors | null=>{ return (control: AbstractControl): ValidationErrors | null=>{
const fa = control.get(arrayToCheck) as FormArray; const fa = control.get(arrayToCheck) as FormArray;
if(fa.length === 0){ if(fa.length === 0){
return {emptyArray: true}; return {[EditorCustomValidatorsEnum.emptyArray]: true};
} }
return null; return null;
} }
} }
public pagesHaveAtLeastOneSection(pagesArrayName:string,sectionsArrayName:string ): ValidatorFn{
return (control: AbstractControl): ValidationErrors | null=>{
const pages = control.get(pagesArrayName) as FormArray;
const sections = control.get(sectionsArrayName) as FormArray;
const pageIdsArray = pages.controls.map(page=>page.get('id').value);
const sectionsPageIds = sections.controls.map(section=> section.get('page').value);
let invalidMessage = null;
pageIdsArray.forEach(pageId=>{
if(!sectionsPageIds.includes(pageId)){
invalidMessage = {[EditorCustomValidatorsEnum.atLeastOneSectionInPage]:true};
}
})
return invalidMessage;
}
}
public sectionHasAtLeastOneChildOf(fieldsetsArrayName, sectionsArrayName): ValidatorFn{
return (control: AbstractControl): ValidationErrors | null=>{
const fieldsets = control.get(fieldsetsArrayName) as FormArray;
const sections = control.get(sectionsArrayName) as FormArray;
if((fieldsets && fieldsets.length) || (sections && sections.length)){
return null;
}
return {[EditorCustomValidatorsEnum.sectionMustHaveOneChild] : true};
}
}
} }
export enum EditorCustomValidatorsEnum{
sectionMustHaveOneChild = "sectionMustHaveOneChild",
atLeastOneSectionInPage = 'atLeastOneSectionInPage',
emptyArray="emptyArray"
}

View File

@ -40,7 +40,7 @@
<span (click)="stepper.selectedIndex=idx" <span (click)="stepper.selectedIndex=idx"
class="stepper-title-label" class="stepper-title-label"
[ngClass]="{'stepper-title-label-locked': !isStepUnlocked(idx),'stepper-title-label-completed':idx < stepper.selectedIndex} "> [ngClass]="{'stepper-title-label-locked': !isStepUnlocked(idx),'stepper-title-label-completed':idx < stepper.selectedIndex} ">
<ng-container *ngIf="isStepCompleted(idx) else numberLabel"> <ng-container *ngIf="(step.completed &&(idx!=steps.length-1)) else numberLabel">
<mat-icon style="font-size:0.7em; height: 0px;">done</mat-icon> <mat-icon style="font-size:0.7em; height: 0px;">done</mat-icon>
</ng-container> </ng-container>
<ng-template #numberLabel> <ng-template #numberLabel>
@ -119,7 +119,8 @@
<mat-horizontal-stepper [linear]="true" #stepper class="stepper" (selectionChange)="onMatStepperSelectionChange($event)" style="padding-left: 8px; padding-right: 15px;"> <mat-horizontal-stepper [linear]="true" #stepper class="stepper" (selectionChange)="onMatStepperSelectionChange($event)" style="padding-left: 8px; padding-right: 15px;">
<mat-step [label]="'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.TITLE' | translate" [stepControl]="basicInfo"> <!-- IMPORTANT TO BE !INVALID (WHEN THE TEMPLATE IS FINALIZED THE CONTORLS ARE DISABLED) -->
<mat-step [label]="'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.TITLE' | translate" [completed]="(!form.get('label').invalid && !form.get('description').invalid && !form.get('language').invalid)" >
<!-- <ng-template matStepLabel>{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.TITLE' | translate}} <!-- <ng-template matStepLabel>{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.TITLE' | translate}}
</ng-template> --> </ng-template> -->
<div class="row"> <div class="row">
@ -127,7 +128,7 @@
<div class="heading">1.1 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-NAME'| translate}} *</div> <div class="heading">1.1 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-NAME'| translate}} *</div>
<div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-NAME-HINT'| translate}}</div> <div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-NAME-HINT'| translate}}</div>
<mat-form-field class="full-width basic-info-input"> <mat-form-field class="full-width basic-info-input">
<input matInput formControlName="label" <input matInput [formControl]="form.get('label')"
placeholder="{{'DATASET-PROFILE-EDITOR.FIELDS.DATASET-TITLE' | translate}}" required> placeholder="{{'DATASET-PROFILE-EDITOR.FIELDS.DATASET-TITLE' | translate}}" required>
<mat-error *ngIf="form.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | <mat-error *ngIf="form.get('label').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' |
translate}} translate}}
@ -139,7 +140,7 @@
<!-- <div class="hint">{{'DMP-EDITOR.MAIN-INFO.HINT' | translate}}</div> --> <!-- <div class="hint">{{'DMP-EDITOR.MAIN-INFO.HINT' | translate}}</div> -->
<div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-DESCRIPTION-HINT'| translate}}</div> <div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-DESCRIPTION-HINT'| translate}}</div>
<mat-form-field class="full-width basic-info-input"> <mat-form-field class="full-width basic-info-input">
<textarea matInput formControlName="description" cdkTextareaAutosize cdkAutosizeMinRows="4" cdkAutosizeMaxRows="5" <textarea matInput [formControl]="form.get('description')" cdkTextareaAutosize cdkAutosizeMinRows="4" cdkAutosizeMaxRows="5"
placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-DESCRIPTION-PLACEHOLDER'| translate}}" required> placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-DESCRIPTION-PLACEHOLDER'| translate}}" required>
</textarea> </textarea>
<mat-error *ngIf="form.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' <mat-error *ngIf="form.get('description').hasError('required')">{{'GENERAL.VALIDATION.REQUIRED'
@ -153,7 +154,7 @@
<div class="heading">1.3 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-LANGUAGE'| translate}} *</div> <div class="heading">1.3 {{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-LANGUAGE'| translate}} *</div>
<mat-form-field class="full-width basic-info-input"> <mat-form-field class="full-width basic-info-input">
<!-- <input matInput formControlName="description" placeholder="{{'DATASET-PROFILE-EDITOR.FIELDS.DATASET-DESCRIPTION' | translate}}" required> --> <!-- <input matInput formControlName="description" placeholder="{{'DATASET-PROFILE-EDITOR.FIELDS.DATASET-DESCRIPTION' | translate}}" required> -->
<mat-select formControlName="language" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-SELECT-LANGUAGE'| translate}}"> <mat-select [formControl]="form.get('language')" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.DATASET-TEMPLATE-SELECT-LANGUAGE'| translate}}">
<mat-option *ngFor="let lang of getLanguageInfos()" [value]="lang.code"> <mat-option *ngFor="let lang of getLanguageInfos()" [value]="lang.code">
{{ lang.name }} {{ lang.name }}
</mat-option> </mat-option>
@ -181,7 +182,7 @@
</div> </div>
</div> </div>
</mat-step> --> </mat-step> -->
<mat-step [label]="'DATASET-PROFILE-EDITOR.STEPS.FORM.TITLE' | translate" [stepControl]="form"> <mat-step [label]="'DATASET-PROFILE-EDITOR.STEPS.FORM.TITLE' | translate" [completed]="form.valid">
<!-- <ng-template matStepLabel>{{'DATASET-PROFILE-EDITOR.STEPS.FORM.TITLE' | translate}}</ng-template> --> <!-- <ng-template matStepLabel>{{'DATASET-PROFILE-EDITOR.STEPS.FORM.TITLE' | translate}}</ng-template> -->
<div class="row"> <div class="row">
@ -200,7 +201,8 @@
(removeEntry)="onRemoveEntry($event)" (removeEntry)="onRemoveEntry($event)"
[itemSelected]="selectedTocEntry" [itemSelected]="selectedTocEntry"
[viewOnly]="viewOnly" [viewOnly]="viewOnly"
(dataNeedsRefresh)="onDataNeedsRefresh()"> (dataNeedsRefresh)="onDataNeedsRefresh()"
[colorizeInvalid]="colorizeInvalid">
</dataset-profile-table-of-contents> </dataset-profile-table-of-contents>
</div> </div>
</div> </div>
@ -224,6 +226,7 @@
<div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.PAGE-NAME-HINT' | translate}}</div> <div class="hint">{{'DATASET-PROFILE-EDITOR.STEPS.PAGE-INFO.PAGE-NAME-HINT' | translate}}</div>
<mat-form-field> <mat-form-field>
<input type="text" matInput formControlName="title"> <input type="text" matInput formControlName="title">
<mat-error >{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
@ -402,7 +405,7 @@
<!-- SAVE BUTTON --> <!-- SAVE BUTTON -->
<div class="col-6 d-flex" *ngIf="!viewOnly"> <div class="col-6 d-flex" *ngIf="!viewOnly">
<div class="row mt-4"> <div class="row mt-4">
<ng-container *ngIf="false"> <ng-container *ngIf="true">
<button mat-raised-button class="col-auto mr-2" color="primary" type="button col-auto" <button mat-raised-button class="col-auto mr-2" color="primary" type="button col-auto"
(click)='checkFormValidation()' (click)='checkFormValidation()'
[disabled]="form.valid">{{'DATASET-PROFILE-EDITOR.ACTIONS.VALIDATE' | translate}}</button> [disabled]="form.valid">{{'DATASET-PROFILE-EDITOR.ACTIONS.VALIDATE' | translate}}</button>
@ -440,12 +443,20 @@
</div> </div>
</ng-container> </ng-container>
<!--
<div class="row"> <!-- <div class="row">
<button (click)="printForm()"> <button (click)="printForm()">
console form console form
</button> </button>
</div> --> </div> -->
<!--
<div *ngIf="form">{{form.value | json}}</div>
<br>
<br>
<div class="row">
{{form.controls?.sections.value |json}}
</div> -->
<!-- {{form.value | json}} --> <!-- {{form.value | json}} -->
<!-- <div class="row"> <!-- <div class="row">

View File

@ -41,7 +41,7 @@ import { Rule } from '@app/core/model/dataset-profile-definition/rule';
import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style'; import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style';
import { invalid } from '@angular/compiler/src/render3/view/util'; import { invalid } from '@angular/compiler/src/render3/view/util';
import { SideNavService } from '@app/core/services/sidenav/side-nav.sevice'; import { SideNavService } from '@app/core/services/sidenav/side-nav.sevice';
import { EditorCustomValidators } from './custom-validators/editor-custom-validators'; import { EditorCustomValidators, EditorCustomValidatorsEnum } from './custom-validators/editor-custom-validators';
import { CustomErrorValidator } from '@common/forms/validation/custom-validator'; import { CustomErrorValidator } from '@common/forms/validation/custom-validator';
import { STEPPER_ANIMATIONS } from './animations/animations'; import { STEPPER_ANIMATIONS } from './animations/animations';
const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json'); const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json');
@ -72,6 +72,8 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
errorMessages: string[] = []; errorMessages: string[] = [];
tocEntryEnumValues = ToCEntryType; tocEntryEnumValues = ToCEntryType;
colorizeInvalid:boolean = false;
customEditorValidators = new EditorCustomValidators(); customEditorValidators = new EditorCustomValidators();
@ -187,7 +189,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
} else { } else {
this.dataModel = new DatasetProfileEditorModel(); this.dataModel = new DatasetProfileEditorModel();
this.form = this.dataModel.buildForm(); this.form = this.dataModel.buildForm();
this.form.setValidators([this.customEditorValidators._atLeastOneElementListValidator('pages'), this.customEditorValidators._atLeastOneElementListValidator('sections')]) this.form.setValidators([this.customEditorValidators.atLeastOneElementListValidator('pages'), this.customEditorValidators.pagesHaveAtLeastOneSection('pages', 'sections')])
if (this.dataModel.status === DatasetProfileEnum.FINALIZED) { if (this.dataModel.status === DatasetProfileEnum.FINALIZED) {
this.form.disable(); this.form.disable();
this.viewOnly = true; this.viewOnly = true;
@ -207,10 +209,11 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
prepareForm() { prepareForm() {
this.visibilityRulesService.buildVisibilityRules([],this.form); this.visibilityRulesService.buildVisibilityRules([],this.form);
this.form.setValidators([this.customEditorValidators._atLeastOneElementListValidator('pages'), this.customEditorValidators._atLeastOneElementListValidator('pages')]); this.form.setValidators([this.customEditorValidators.atLeastOneElementListValidator('pages'),this.customEditorValidators.pagesHaveAtLeastOneSection('pages', 'sections')]);
this.form.valueChanges this.form.valueChanges
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(change => { .subscribe(change => {
// this.datasetProfileService.preview(this.form.value) // this.datasetProfileService.preview(this.form.value)
// .pipe(takeUntil(this._destroyed)) // .pipe(takeUntil(this._destroyed))
// .subscribe(dataset => { // .subscribe(dataset => {
@ -230,8 +233,6 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
this.selectedTocEntry = tocentries[0]; this.selectedTocEntry = tocentries[0];
} }
//this.getPreview();
} }
onIsMultiplicityEnabledChange(isMultiplicityEnabled: boolean) { onIsMultiplicityEnabledChange(isMultiplicityEnabled: boolean) {
@ -241,11 +242,11 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
} }
} }
addSection() { // addSection() {
const section: SectionEditorModel = new SectionEditorModel(); // const section: SectionEditorModel = new SectionEditorModel();
this.dataModel.sections.push(section); // this.dataModel.sections.push(section);
(<FormArray>this.form.get('sections')).push(section.buildForm()); // (<FormArray>this.form.get('sections')).push(section.buildForm());
} // }
addPage() { addPage() {
const page: PageEditorModel = new PageEditorModel(this.dataModel.pages.length); const page: PageEditorModel = new PageEditorModel(this.dataModel.pages.length);
@ -376,6 +377,11 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
}); });
} }
updateValidity(){
// this.form.updateValueAndValidity();
console.log('updagted');
}
getFilenameFromContentDispositionHeader(header: string): string { getFilenameFromContentDispositionHeader(header: string): string {
const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g); const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);
@ -399,15 +405,19 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
} }
checkFormValidation() { checkFormValidation() {
if (!this.form.valid) { this.colorizeInvalid = true;
this.nestedIndex = -1; this.printMyErrors(this.form);
this.form.markAllAsTouched();
this.printErrors(this.form);
this.showValidationErrorsDialog(); // if (!this.form.valid) {
this.nestedCount = []; // this.nestedIndex = -1;
this.nestedIndex = 0; // this.form.markAllAsTouched();
this.errorMessages = []; // this.printErrors(this.form);
} // this.showValidationErrorsDialog();
// this.nestedCount = [];
// this.nestedIndex = 0;
// this.errorMessages = [];
// }
} }
printErrors(rootform: FormGroup) { printErrors(rootform: FormGroup) {
@ -740,7 +750,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
// this.dataModel.pages.push(page); // this.dataModel.pages.push(page);
pagesArray.push(pageForm); pagesArray.push(pageForm);
// this.form.updateValueAndValidity();
this.refreshToCEntries(); this.refreshToCEntries();
this.selectedTocEntry = this._findTocEntryById(pageForm.get('id').value, this.toCEntries); this.selectedTocEntry = this._findTocEntryById(pageForm.get('id').value, this.toCEntries);
@ -757,6 +767,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
section.page = parent.id; section.page = parent.id;
section.ordinal = sectionsArray.length; section.ordinal = sectionsArray.length;
sectionsArray.push(section.buildForm()); sectionsArray.push(section.buildForm());
// this.form.updateValueAndValidity();
} else if( parent.type == ToCEntryType.Section) { //SUBSECTION OF SECTION } else if( parent.type == ToCEntryType.Section) { //SUBSECTION OF SECTION
sectionsArray = parent.form.get('sections') as FormArray; sectionsArray = parent.form.get('sections') as FormArray;
@ -774,6 +785,8 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
const sectionAdded = sectionsArray.at(sectionsArray.length -1) as FormGroup; const sectionAdded = sectionsArray.at(sectionsArray.length -1) as FormGroup;
sectionAdded.setValidators(this.customEditorValidators.sectionHasAtLeastOneChildOf('fieldSets','sections'));
sectionAdded.updateValueAndValidity();
this.refreshToCEntries(); this.refreshToCEntries();
@ -817,7 +830,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
break; break;
} }
// this.refreshToCEntries(); this.form.updateValueAndValidity();
} }
@ -912,27 +925,29 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
pages.removeAt(pageIndex); pages.removeAt(pageIndex);
//clean up sections of removed page //clean up sections of removed page
const sections = (this.form.get('sections') as FormArray).controls; const sections = (this.form.get('sections') as FormArray);
const updatedSections = new FormArray([]); const sectionsIndexToBeRemoved = [];
for (let i = 0; i < sections.length; i++) { sections.controls.forEach((section,idx)=>{
let section = sections[i]; if(section.get('page').value === tce.id){
sectionsIndexToBeRemoved.push(idx);
if (section.get('page').value != tce.id) {
updatedSections.push(section);
} }
} });
//replace sections value
this.form.controls.sections = updatedSections;
//update page orders if(sectionsIndexToBeRemoved.length){
sectionsIndexToBeRemoved.reverse().forEach(index=>{
sections.removeAt(index);
});
}
//update page ordinals
for(let i=0; i<pages.length; i++){ for(let i=0; i<pages.length; i++){
pages.at(i).get('ordinal').patchValue(i); pages.at(i).get('ordinal').patchValue(i);
} }
//update validity //update validity
this.form.controls.sections.updateValueAndValidity(); // this.form.controls.sections.updateValueAndValidity();
} }
break; break;
@ -1028,6 +1043,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
//in case selectedtocentrhy is child of the removed element //in case selectedtocentrhy is child of the removed element
this.refreshToCEntries(); this.refreshToCEntries();
this.form.updateValueAndValidity();
} }
@ -1339,22 +1355,22 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
get basicInfo(){ // get basicInfo(){
const label = this.form.get('label'); // const label = this.form.get('label');
const description = this.form.get('description'); // const description = this.form.get('description');
const language = this.form.get('language'); // const language = this.form.get('language');
const fg = new FormGroup({ // const fg = new FormGroup({
label: label, // label: label,
description: description, // description: description,
language: language // language: language
}) // })
return fg; // return fg;
} // }
@ -1421,14 +1437,12 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
} }
isStepCompleted(stepIndex: number){ isStepCompleted(stepIndex: number){ //TODO NA TO DOUME MIPOS DEN XREIAZETAI
let stepCompleted = false; let stepCompleted = false;
this.steps.forEach((step,index)=>{ this.steps.forEach((step,index)=>{
if(stepIndex === index){ if(stepIndex === index){
if(step.stepControl){ stepCompleted = step.completed;
stepCompleted = step.stepControl.valid;
}
} }
}); });
@ -1437,13 +1451,17 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
isStepUnlocked(stepIndex: number): boolean{ isStepUnlocked(stepIndex: number): boolean{
if(stepIndex === 0) return true; if(stepIndex === 0) return true;
if(stepIndex <0 ) return false;
//if previous step is valid then unlock //if previous step is valid then unlock
let stepUnlocked: boolean = false; let stepUnlocked: boolean = false;
if(!this.isStepUnlocked(stepIndex -1)) return false;
this.steps.forEach((step,index)=>{ this.steps.forEach((step,index)=>{
if(index+1 == stepIndex){//previous step if(index+1 == stepIndex){//previous step
if(step.stepControl.valid){
if(step.completed){
stepUnlocked = true; stepUnlocked = true;
} }
} }
@ -1453,27 +1471,27 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
} }
validateStep(step: CdkStep){ validateStep(step: CdkStep){
if(step.hasError){ // if(step.hasError){
this.printMyErrors(this.form); // this.printMyErrors(this.form);
} // }
} }
getFormValidationErrors() { // getFormValidationErrors() {
Object.keys(this.form.controls).forEach(key => { // Object.keys(this.form.controls).forEach(key => {
const controlErrors: ValidationErrors = this.form.get(key).errors; // const controlErrors: ValidationErrors = this.form.get(key).errors;
if (controlErrors != null) { // if (controlErrors != null) {
Object.keys(controlErrors).forEach(keyError => { // Object.keys(controlErrors).forEach(keyError => {
console.log('Key control: ' + key + ', keyError: ' + keyError + ', err value: ', controlErrors[keyError]); // console.log('Key control: ' + key + ', keyError: ' + keyError + ', err value: ', controlErrors[keyError]);
}); // });
} // }
}); // });
if(this.form.invalid){ // if(this.form.invalid){
console.log('this form is invalid!'); // console.log('this form is invalid!');
console.log(this.form.errors); // console.log(this.form.errors);
} // }
} // }
@ -1481,11 +1499,26 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
const errmess: string[] = []; const errmess: string[] = [];
Object.keys(errors).forEach(keyError => { Object.keys(errors).forEach(keyError => {
if (typeof errors[keyError] === 'boolean') {
errmess.push(numbering + ' ' + key + ' is ' + keyError); switch(keyError){
} else { case EditorCustomValidatorsEnum.atLeastOneSectionInPage:
errmess.push(numbering + ' ' + key + ': ' + keyError + ': ' + JSON.stringify(errors[keyError])); errmess.push('Each section must have at least one subsection');
break;
case EditorCustomValidatorsEnum.emptyArray:
errmess.push(numbering+" needs more information.")
break;
case EditorCustomValidatorsEnum.sectionMustHaveOneChild:
errmess.push(numbering+" must have either subsection or input sets.")
break;
default:
if (typeof errors[keyError] === 'boolean') {
errmess.push(numbering + ' ' + key + ' is ' + keyError);
} else {
errmess.push(numbering + ' ' + key + ': ' + keyError + ': ' + JSON.stringify(errors[keyError]));
}
} }
}); });
return errmess; return errmess;
@ -1495,59 +1528,67 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
printMyErrors(form: AbstractControl){ printMyErrors(form: AbstractControl){
// this._printToCentriesErrrors(this.toCEntries); // this._printToCentriesErrrors(this.toCEntries);
const result = this._getErrors(form); const result = this._getErrors(form);
// console.log('result', result);
// console.log('got errors ');
// console.log(result); // console.log(result);
if(result){ if(result && form.invalid){
form.markAllAsTouched();
const errmess:string[] = []; const errmess:string[] = [];
if(result.length){
form.markAllAsTouched();
let indexes:number[] = []; let indexes:number[] = [];
///search in pages,sections and fieldsets for the id ///search in pages,sections and fieldsets for the id
result.forEach((err,i)=>{ result.forEach((err,i)=>{
const entry = this._findTocEntryById(err.id, this.toCEntries); const entry = this._findTocEntryById(err.id, this.toCEntries);
if(entry){ if(entry){
// errmess.push(`Error on ${entry.numbering} ${entry.label} . ${err.key}`); // errmess.push(`Error on ${entry.numbering} ${entry.label} . ${err.key}`);
errmess.push(...this._buildErrorMessage(err.errors, entry.numbering, err.key)); errmess.push(...this._buildErrorMessage(err.errors, entry.numbering, err.key));
indexes.push(i); indexes.push(i);
} }
}); });
indexes.reverse().forEach(index=>{ indexes.reverse().forEach(index=>{
result.splice(index,1); result.splice(index,1);
});
indexes = [];
//searching in fields
const fieldsets = this._getAllFieldSets(this.toCEntries);
result.forEach((err,i)=>{
fieldsets.filter(fs=>{
let fieldFound = false;
(fs.form.get('fields') as FormArray).controls.forEach(field=>{
if(field.get('id').value === err.id){
fieldFound = true;
indexes.push(i);
}
});
return fieldFound;
})
//printing fieldsets that the field missing
.forEach(fs=>{
// errmess.push(`Missing input in ${fs.numbering} ${fs.label} . ${err.key}`);
errmess.push(...this._buildErrorMessage(err.errors, fs.numbering, err.key));
}); });
});
indexes.reverse().forEach(index=>{ indexes = [];
result.splice(index,1); //searching in fields
}); const fieldsets = this._getAllFieldSets(this.toCEntries);
result.forEach((err,i)=>{
fieldsets.filter(fs=>{
let fieldFound = false;
(fs.form.get('fields') as FormArray).controls.forEach(field=>{
if(field.get('id').value === err.id){
fieldFound = true;
indexes.push(i);
}
});
return fieldFound;
})
//printing fieldsets that the field missing
.forEach(fs=>{
// errmess.push(`Missing input in ${fs.numbering} ${fs.label} . ${err.key}`);
errmess.push(...this._buildErrorMessage(err.errors, fs.numbering, err.key));
});
});
result.forEach(err=>{ indexes.reverse().forEach(index=>{
errmess.push(`Missing ${err.key}` ); result.splice(index,1);
}) });
result.forEach(err=>{
// console.log(err);
if(err.key){
errmess.push(`Missing ${err.key}` );
}else{
errmess.push('Make sure you provide a section and a subsection');
}
// errmess.push(...this._buildErrorMessage(err.errors,"", err.key) );
})
}
// console.log(result); // console.log(result);
@ -1627,11 +1668,7 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
private _getErrors(aControl: AbstractControl):InvalidControl[]{ private _getErrors(aControl: AbstractControl):InvalidControl[]{
// if(aControl instanceof FormGroup) console.log('is Formgroup');
// if(aControl instanceof FormControl)console.log( aControl.errors);
// if(aControl instanceof FormArray) console.log('isForm array');
// console
if(aControl.valid) return; if(aControl.valid) return;
let controlType = 'control'; let controlType = 'control';
@ -1650,14 +1687,11 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
const keys = Object.keys(controls); const keys = Object.keys(controls);
keys.forEach(key=>{ keys.forEach(key=>{
const control = controls[key]; const control = controls[key];
if(control.valid) return; if(!control.invalid) return; //// !!!!! Important to be !invalid. (In case the template is finalized)
if(control instanceof FormControl){ if(control instanceof FormControl){
const ctrl = control as FormControl; const ctrl = control as FormControl;
// console.log('Control ', key,' of Formgroup ', aControl.get('id'), ' has errors', ctrl.errors);
// console.log(aControl)
invalidControls.push({ invalidControls.push({
errors:ctrl.errors, errors:ctrl.errors,
id: ctrl.get('id')? ctrl.get('id').value: null, id: ctrl.get('id')? ctrl.get('id').value: null,
@ -1674,26 +1708,38 @@ export class DatasetProfileEditorComponent extends BaseComponent implements OnIn
// invalidSubControls:[]//TODO TO CHECK // invalidSubControls:[]//TODO TO CHECK
// }); // });
// } // }
if(control.errors){
// invalidControls.push({
// id: aControl.get('id')? aControl.get('id').value: null,
// errors:aControl.errors,
// key: aControl.get('title')? aControl.get('title').value: 'unspecified',
// invalidSubControls:[]//TODO TO CHECK
// });
invalidControls.push({
errors:control.errors, //THE ONE WE REMOVED
id: control.get('id')? control.get('id').value: null, // if(control.errors){
invalidSubControls: [], // // invalidControls.push({
key: key // // id: aControl.get('id')? aControl.get('id').value: null,
}); // // errors:aControl.errors,
} // // key: aControl.get('title')? aControl.get('title').value: 'unspecified',
// // invalidSubControls:[]//TODO TO CHECK
// // });
// invalidControls.push({
// errors:control.errors,
// id: control.get('id')? control.get('id').value: null,
// invalidSubControls: [],
// key: key
// });
// }
invalidControls.push(...this._getErrors(control)) ; invalidControls.push(...this._getErrors(control)) ;
} }
}); });
/**In case there is an error in a formgroup then the validator probably is custom */
if(aControl.errors){
invalidControls.push({
errors:aControl.errors,
id: aControl.get('id')? aControl.get('id').value: null,
invalidSubControls: [],
key: aControl.get('title')?aControl.get('title').value: null
});
}
break; break;
case 'fa': case 'fa':

View File

@ -22,7 +22,7 @@
[ngStyle]="{'font-size' : (parentLink.type == tocEntryType.FieldSet? '.9rem':'1rem')}" [ngStyle]="{'font-size' : (parentLink.type == tocEntryType.FieldSet? '.9rem':'1rem')}"
> --> > -->
<span class="table-label-element" [ngClass]="{'table-label-element-active': itemSelected?.id == parentLink?.id}" (click)="itemClicked(parentLink)" <span class="table-label-element" [ngClass]="{'table-label-element-active': itemSelected?.id == parentLink?.id, 'text-danger': colorError()}" (click)="itemClicked(parentLink)"
[ngStyle]="{'font-size' : (parentLink.type == tocEntryType.FieldSet? '.9rem':'1rem')}" [ngStyle]="{'font-size' : (parentLink.type == tocEntryType.FieldSet? '.9rem':'1rem')}"
> >
<!-- {{parentLink?.numbering}} {{parentLink?.label? parentLink?.label : 'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate}} --> <!-- {{parentLink?.numbering}} {{parentLink?.label? parentLink?.label : 'DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.UNTITLED' | translate}} -->
@ -33,10 +33,14 @@
</div> </div>
<div class="col-auto d-flex align-items-center" > <div class="col-auto d-flex align-items-center" >
<span class="badge-ball"
*ngIf="!(!((parentLink?.subEntriesType == tocEntryType.FieldSet) && !selectedItemInLinks) || itemSelected?.id == parentLink.id ||isDragging)"> <ng-container *ngIf="!(!((parentLink?.subEntriesType == tocEntryType.FieldSet) && !selectedItemInLinks) || itemSelected?.id == parentLink.id ||isDragging)">
{{parentLink.subEntries?.length}} <mat-icon class="text-danger" style="font-size: 1.4em;" *ngIf="!colorError() && parentLink?.form.invalid && colorizeInvalid && allFieldsAreTouched(parentLink?.form)">priority_high</mat-icon>
</span> <span class="badge-ball"
>
{{parentLink.subEntries?.length}}
</span>
</ng-container>
<span style="cursor: pointer;" (click)="deleteEntry(parentLink)" <span style="cursor: pointer;" (click)="deleteEntry(parentLink)"
@ -109,7 +113,8 @@
[overContainerId]="overContainerId" [overContainerId]="overContainerId"
[isDragging]="isDragging" [isDragging]="isDragging"
[draggingItemId]="draggingItemId" [draggingItemId]="draggingItemId"
[parentRootId]="parentRootId"> [parentRootId]="parentRootId"
[colorizeInvalid]="colorizeInvalid">
</app-dataset-profile-table-of-contents-internal-section> </app-dataset-profile-table-of-contents-internal-section>

View File

@ -1,7 +1,7 @@
import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop'; import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';
import { DOCUMENT } from '@angular/common'; import { DOCUMENT } from '@angular/common';
import { Component, EventEmitter, Inject, Input, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; import { Component, EventEmitter, Inject, Input, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
import { FormArray } from '@angular/forms'; import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms';
import { BaseComponent } from '@common/base/base.component'; import { BaseComponent } from '@common/base/base.component';
import { Foo, ToCEntry, ToCEntryType } from '../table-of-contents-entry'; import { Foo, ToCEntry, ToCEntryType } from '../table-of-contents-entry';
@ -31,6 +31,8 @@ export class DatasetProfileTableOfContentsInternalSection extends BaseComponent
@Input() draggingItemId: string; @Input() draggingItemId: string;
@Input() parentRootId: string; @Input() parentRootId: string;
@Input() colorizeInvalid:boolean = false;
@Input() viewOnly: boolean; @Input() viewOnly: boolean;
// @Input() dropListGroup: Set<string> = new Set<string>(); // @Input() dropListGroup: Set<string> = new Set<string>();
@Input() dropListGroup: string[]; @Input() dropListGroup: string[];
@ -229,4 +231,78 @@ export class DatasetProfileTableOfContentsInternalSection extends BaseComponent
return tocEntryFound? tocEntryFound: null; return tocEntryFound? tocEntryFound: null;
} }
colorError():boolean{
if(!this.colorizeInvalid) return false;
const form = this.parentLink.form;
if(!form || form.valid || !form.touched) return false;
const allFieldsAreTouched = this.allFieldsAreTouched(form);
//fieldset may have errros that are inside its controls and not in the fieldsetFormGroup
if(this.parentLink.type === this.tocEntryType.FieldSet && allFieldsAreTouched) return true;
if(form.errors && allFieldsAreTouched) return true;
//checking form controls if have errors
let hasErrors = false;
if(allFieldsAreTouched){
if(form instanceof FormGroup){
const formGroup = form as FormGroup;
const controls = Object.keys(formGroup.controls);
controls.forEach(control=>{
if(formGroup.get(control).errors){
hasErrors = true;
}
})
}
}
return hasErrors;
}
allFieldsAreTouched(aControl:AbstractControl){//auto na testaroume
if(!aControl|| aControl.untouched) return false;
if(aControl instanceof FormControl){
return aControl.touched;
}else if(aControl instanceof FormGroup){
const controlKeys = Object.keys((aControl as FormGroup).controls);
let areAllTouched = true;
controlKeys.forEach(key=>{
if(!this.allFieldsAreTouched(aControl.get(key))){
areAllTouched = false;
}
})
// const areAllTouched = controlKeys.reduce((acc, key)=>acc && this._allFieldsAreTouched(aControl.get(key)), true);
return areAllTouched;
}else if(aControl instanceof FormArray){
const controls = (aControl as FormArray).controls;
// const areAllTouched = controls.reduce((acc, control)=>acc && this._allFieldsAreTouched(control), true);
let areAllTouched = true;
// controls.reduce((acc, control)=>acc && this._allFieldsAreTouched(control), true);
controls.forEach(control=>{
if(!this.allFieldsAreTouched(control)){
areAllTouched = false;
}
});
return areAllTouched;
}
return false;
}
} }

View File

@ -22,6 +22,7 @@
[draggingItemId]="draggingItemId" [draggingItemId]="draggingItemId"
[parentRootId]="ROOT_ID" [parentRootId]="ROOT_ID"
style="padding-right: 1em;" style="padding-right: 1em;"
[colorizeInvalid]="colorizeInvalid"
></app-dataset-profile-table-of-contents-internal-section> ></app-dataset-profile-table-of-contents-internal-section>
<!-- <span *ngFor="let link of links; let i = index" (click)="toggle(link); goToStep(link);" class="docs-link mt-0"> <!-- <span *ngFor="let link of links; let i = index" (click)="toggle(link); goToStep(link);" class="docs-link mt-0">

View File

@ -50,6 +50,7 @@ export class DatasetProfileTableOfContents extends BaseComponent implements OnIn
@Output() dataNeedsRefresh = new EventEmitter<void>(); @Output() dataNeedsRefresh = new EventEmitter<void>();
@Input() itemSelected: ToCEntry; @Input() itemSelected: ToCEntry;
@Input() colorizeInvalid: boolean = false;
// @Input() set itemSelected(entry:ToCEntry){ // @Input() set itemSelected(entry:ToCEntry){
// this._itemSelected = entry; // this._itemSelected = entry;

View File

@ -76,11 +76,11 @@
} }
} }
::ng-deep .mat-form-field-wrapper { :host ::ng-deep .mat-form-field-wrapper {
background-color: white !important; background-color: white !important;
padding-bottom: 0 !important; padding-bottom: 0 !important;
} }
::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { :host ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix {
padding: 0.3rem 0rem 0.6rem 0rem !important; padding: 0.3rem 0rem 0.6rem 0rem !important;
} }

View File

@ -10,11 +10,11 @@
padding: 0.4rem; padding: 0.4rem;
} }
::ng-deep .mat-form-field-wrapper { :host ::ng-deep .mat-form-field-wrapper {
background-color: white !important; background-color: white !important;
padding-bottom: 0 !important; padding-bottom: 0 !important;
} }
::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix { :host ::ng-deep .mat-form-field-appearance-outline .mat-form-field-infix {
padding: 0.3rem 0rem 0.6rem 0rem !important; padding: 0.3rem 0rem 0.6rem 0rem !important;
} }

View File

@ -122,7 +122,7 @@
background-color: #2e74b649; background-color: #2e74b649;
} }
::ng-deep .mat-form-field-wrapper { :host ::ng-deep .mat-form-field-wrapper {
background-color: white !important; background-color: white !important;
padding-bottom: 0 !important; padding-bottom: 0 !important;
} }