diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.ts index c3f45585e..2cd1cc02f 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.ts @@ -61,8 +61,8 @@ export class FormCompositeFieldComponent { ((this.form.get('multiplicityItems'))).removeAt(0); - this.visibilityRulesService.annihilateId(compositeFieldId); - fieldIds.forEach( x => this.visibilityRulesService.annihilateId(x)); + this.visibilityRulesService.removeAllIdReferences(compositeFieldId); + fieldIds.forEach( x => this.visibilityRulesService.removeAllIdReferences(x)); } deleteMultipeFieldFromCompositeFormGroup() { @@ -73,8 +73,8 @@ export class FormCompositeFieldComponent { const fieldIds = (this.form.get('fields') as FormArray).controls.map(control => control.get('id').value) as string[]; - this.visibilityRulesService.annihilateId(currentId); - fieldIds.forEach(x => this.visibilityRulesService.annihilateId(x)); + this.visibilityRulesService.removeAllIdReferences(currentId); + fieldIds.forEach(x => this.visibilityRulesService.removeAllIdReferences(x)); (parent as FormArray).removeAt(index); (parent as FormArray).controls.forEach((control, i)=>{ diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts index 248e2712e..a07ea16ca 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-section/form-section.component.ts @@ -121,12 +121,26 @@ export class FormSectionComponent implements OnInit, OnChanges { const newId = idMappings.find(y=> y.old === x.sourceControlId); return {...x, sourceControlId: newId.new}; }); - const visRule: VisibilityRule = { - targetControlId: idMappings.find(x => x.old === element.id).new, - sourceVisibilityRules: updatedRules - } + // const visRule: VisibilityRule = { + // targetControlId: idMappings.find(x => x.old === element.id).new, + // sourceVisibilityRules: updatedRules + // } + + + const rules = updatedRules.map(x => { + return { + requiredValue: x.sourceControlValue, + sourceField: x.sourceControlId, + targetField: idMappings.find(l=> l.old === element.id).new, + type: '' + } as Rule; + }); + + rules.forEach(rule =>{ + this.visibilityRulesService.addNewRule(rule); + }) - this.visibilityRulesService.appendVisibilityRule(visRule); + // this.visibilityRulesService.appendVisibilityRule(visRule); } } @@ -146,11 +160,26 @@ export class FormSectionComponent implements OnInit, OnChanges { return {...x ,sourceControlId: idMappings.find(y => y.old === element.id).new}; }); - const visRule: VisibilityRule = { - targetControlId: target, - sourceVisibilityRules: updatedRules - } - this.visibilityRulesService.appendVisibilityRule(visRule); + // const visRule: VisibilityRule = { + // targetControlId: target, + // sourceVisibilityRules: updatedRules + // } + + + const rules = updatedRules.map(x =>{ + return { + requiredValue: x.sourceControlValue, + sourceField: x.sourceControlId, + targetField: target, + type: '' + } as Rule; + }) + + rules.forEach(rule =>{ + this.visibilityRulesService.addNewRule(rule); + }) + + // this.visibilityRulesService.appendVisibilityRule(visRule); }); diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts index d18a6300d..2a5d9b381 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts @@ -43,7 +43,10 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit } ngOnInit() { - this.visibilityRulesService.buildVisibilityRules(this.visibilityRules, this.form); + this.tocentries = this.getTocEntries(); + const rules_to_append = this._enrichWithMultiplicityRules(this.tocentries); + + this.visibilityRulesService.buildVisibilityRules([...this.visibilityRules, ...rules_to_append ], this.form); // if (this.form) { // this.form.valueChanges @@ -54,9 +57,7 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit // } this.visibilityRulesInstance.emit(this.visibilityRulesService); - this.tocentries = this.getTocEntries(); - this._enrichWithMultiplicityRules(this.tocentries); this.hiddenEntriesIds = this._findHiddenEntries(this.tocentries); @@ -96,10 +97,10 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit - private _enrichWithMultiplicityRules(tocentries: ToCEntry[]) : void { + private _enrichWithMultiplicityRules(tocentries: ToCEntry[]) : Rule[] { if (tocentries){ - tocentries.forEach(entry => { - if(entry.type === ToCEntryType.Field) return; // * TODO Me to tora implementation den tha ftasei pote edo + return tocentries.map(entry => { + if(entry.type === ToCEntryType.Field) return []; // * TODO Me to tora implementation den tha ftasei pote edo if(entry.type === ToCEntryType.FieldSet){ @@ -109,24 +110,27 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit // * UPDATE KANEI DESTROY TO COMPONENT H NGIF . PITHANOTATA NA XREIASTEI NA TO KANOUME HIDDEN AN THELOUME KATI ALLO const multiplicity = entry.form.get('multiplicity').value; if( (multiplicity.max > 1 ) && (multiplicity.min> 0) && (multiplicity.max >= multiplicity.min)){ // has valid multiplicity - this._createAndAppendVisibilityRule(entry); + return this._createAndAppendVisibilityRule(entry); } } catch { } - - - return + return []; } if(entry.subEntries){ - this._enrichWithMultiplicityRules(entry.subEntries); + return this._enrichWithMultiplicityRules(entry.subEntries); } }) + .reduce((r,c)=>{ return [...c, ...r]},[]); } + return []; } - private _createAndAppendVisibilityRule(entry: ToCEntry): void{ + private _createAndAppendVisibilityRule(entry: ToCEntry): Rule[]{ + + + const rules_to_append = []; if(entry && (entry.type === ToCEntryType.FieldSet)){ @@ -183,7 +187,7 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit const innerDep = original_as_source.filter(x => innerCompositeFieldOriginalIds.includes(x.targetField)); innerDep.forEach(x =>{ const newRule = {...x, sourceField: field.id, targetField: idMappings.find(l => l.original === x.targetField).multiplicityIdValue} as Rule; - this.visibilityRulesService.addNewRule(newRule); + rules_to_append.push(newRule); }) @@ -191,7 +195,7 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit const outerDep = original_as_source.filter(x => !innerCompositeFieldOriginalIds.includes(x.targetField)); outerDep.forEach(x =>{ const newRule = {...x, sourceField: field.id}; - this.visibilityRulesService.addNewRule(newRule); + rules_to_append.push(newRule); }) } @@ -203,14 +207,14 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit const innerDep = original_as_target.filter( x=> innerCompositeFieldOriginalIds.includes(x.sourceField)); innerDep.forEach(x =>{ const newRule = {...x, targetField: field.id, sourceField: idMappings.find(l => l.original === x.sourceField).multiplicityIdValue} as Rule; - this.visibilityRulesService.addNewRule(newRule); + rules_to_append.push(newRule); }) //outer dependencies const outerDep = original_as_target.filter( x=> !innerCompositeFieldOriginalIds.includes(x.sourceField)); outerDep.forEach(x=>{ const newRule = {...x, targetField: field.id} as Rule; - this.visibilityRulesService.addNewRule(newRule); + rules_to_append.push(newRule); }) } @@ -238,13 +242,15 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit compositeFieldAsTargetRules.forEach(x =>{ idCompositeFieldMappings.forEach(l=>{ const newRule = {...x, targetField: l.newValue}; - this.visibilityRulesService.addNewRule(newRule); + rules_to_append.push(newRule); }); }); } } + + return rules_to_append; } private _buildRecursively(form: FormGroup,whatAmI:ToCEntryType):ToCEntry{ diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service.ts index 02b4cfd6f..adbb7d1a4 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service.ts @@ -12,10 +12,12 @@ import { VisibilityRulesContext } from './models/visibility-rules-context'; export class VisibilityRulesService { private readonly VISIBILITY_RULE_LOGIC: 'OR'| 'AND' = 'OR'; + private readonly DEFAULTVISIBILITY = false; private visibilityRuleContext: VisibilityRulesContext; private form: AbstractControl; private elementVisibilityMap = new Map(); + private elementComputationalMap = new Map>(); /// keep saved the values of each form control validity value private _changeMade$ = new Subject(); @@ -40,10 +42,14 @@ export class VisibilityRulesService { public updateValueAndVisibility(id: string, value: any) { const visibilityRules = this.visibilityRuleContext.rules.filter(item => item.sourceVisibilityRules.filter(source => source.sourceControlId === id).length > 0); - visibilityRules.forEach(item => this.evaluateVisibility(item, value)); + visibilityRules.forEach(item => this.evaluateVisibility(item, value, id)); } - private evaluateVisibility(visibilityRule: VisibilityRule, value: any) { + private evaluateVisibility(visibilityRule: VisibilityRule, value: any, sourceId: string) {// source controlId is the same + + const targetId = visibilityRule.targetControlId; + const visibilityMap = this.elementComputationalMap.get(targetId)? this.elementComputationalMap.get(targetId): new Map(); + if (value instanceof Array){ @@ -53,35 +59,97 @@ export class VisibilityRulesService { const isVisible = parsedValues.map(v=>parsedSourceControlValues.includes(v)).reduce((acc,current)=> acc|| current, false); - if(isVisible){ - this._emitChangesIfNeeded(visibilityRule.targetControlId, true); - this.elementVisibilityMap.set(visibilityRule.targetControlId, true); - return; - } + // if(isVisible){ + // this._emitChangesIfNeeded(visibilityRule.targetControlId, true); + // this.elementVisibilityMap.set(visibilityRule.targetControlId, true); + // return; + // } + visibilityMap.set(sourceId, isVisible); + } else { + const visibilityDependencySource = visibilityRule.sourceVisibilityRules.filter( x=> x.sourceControlId === sourceId); + + visibilityDependencySource.forEach(x => { + + const shouldBeHidden = value !== null && (this.parseValue(value) !== this.parseValue(x.sourceControlValue)); + // if(value !== null && ) + visibilityMap.set(sourceId, !shouldBeHidden); + }); + } + + + this.elementComputationalMap.set(targetId, visibilityMap);// unnessecary + + + const isVisible = this._computeVisibility(targetId); + this._emitChangesIfNeeded(targetId, isVisible); + this.elementVisibilityMap.set(targetId, isVisible); + if(!isVisible){ + this.resetControlWithId(this.form, targetId); + } + + + // for (let i = 0; i < visibilityRule.sourceVisibilityRules.length; i++) { + // if (value != null && (this.parseValue(value) !== this.parseValue(visibilityRule.sourceVisibilityRules[i].sourceControlValue))) { + // this._emitChangesIfNeeded(visibilityRule.targetControlId, false); + // this.elementVisibilityMap.set(visibilityRule.targetControlId, false); + // this.resetControlWithId(this.form, visibilityRule.targetControlId); + // //this.updateValueAndVisibility(visibilityRule.targetControlId, null); + // // this.clearValues(targetPathKey); + // return; + // } + // } + // this._emitChangesIfNeeded(visibilityRule.targetControlId, true); + // this.elementVisibilityMap.set(visibilityRule.targetControlId, true); + + // this.updateValueAndVisibility(visibilityRule.targetControlId, null); + } + + + private _computeVisibility(targetId: string) : boolean{ + const visibilityMap = this.elementComputationalMap.get(targetId); + const values = visibilityMap.values(); + let currentVal = values.next(); + let visibilityValues: boolean[] = []; + while(!currentVal.done){ + visibilityValues.push(currentVal.value); + currentVal = values.next(); } - for (let i = 0; i < visibilityRule.sourceVisibilityRules.length; i++) { - if (value != null && (this.parseValue(value) !== this.parseValue(visibilityRule.sourceVisibilityRules[i].sourceControlValue))) { - this._emitChangesIfNeeded(visibilityRule.targetControlId, false); - this.elementVisibilityMap.set(visibilityRule.targetControlId, false); - this.resetControlWithId(this.form, visibilityRule.targetControlId); - //this.updateValueAndVisibility(visibilityRule.targetControlId, null); - // this.clearValues(targetPathKey); - return; - } + + if(visibilityValues.length){ + return visibilityValues.reduce((r, c)=>{ + if(this.VISIBILITY_RULE_LOGIC === 'OR'){ + return r || c; + } else { + return r && c; + } + }, visibilityValues[0]); } - this._emitChangesIfNeeded(visibilityRule.targetControlId, true); - this.elementVisibilityMap.set(visibilityRule.targetControlId, true); - //this.updateValueAndVisibility(visibilityRule.targetControlId, null); + + return this.DEFAULTVISIBILITY; } private resetVisibilityRules() { this.elementVisibilityMap.clear(); this.elementVisibilityMap = new Map(); + this.elementComputationalMap.clear(); + this.elementComputationalMap = new Map>(); + this._populateComputationMap(); /// !IMPORTANT FOR THE AND LOGIC this._changeMade$.next(); } + private _populateComputationMap(): void{ + this.visibilityRuleContext.rules.forEach(rule =>{ + const targetId = rule.targetControlId; + const visibilityMap = this.elementComputationalMap.get(targetId)? this.elementComputationalMap.get(targetId) : new Map< String, boolean>(); + rule.sourceVisibilityRules.forEach(vr =>{ + visibilityMap.set(vr.sourceControlId, this.DEFAULTVISIBILITY); + }); + this.elementComputationalMap.set(targetId, visibilityMap); + }); + } + parseValue(value: any) { if (typeof value === 'string') { if (isNumeric(value)) { return value; } @@ -195,24 +263,26 @@ export class VisibilityRulesService { }).map(x => x.targetControlId); } - public appendVisibilityRule(rule: VisibilityRule): void{ + // public appendVisibilityRule(rule: VisibilityRule): void{ - const existingTargetRule = this.visibilityRuleContext.rules.find( r => r.targetControlId === rule.targetControlId); + // const existingTargetRule = this.visibilityRuleContext.rules.find( r => r.targetControlId === rule.targetControlId); - if(existingTargetRule){ - rule.sourceVisibilityRules.forEach(svr =>{ - existingTargetRule.sourceVisibilityRules.push(svr); - }); - }else{ - this.visibilityRuleContext.rules.push(rule); - } + // if(existingTargetRule){ + // rule.sourceVisibilityRules.forEach(svr =>{ + // existingTargetRule.sourceVisibilityRules.push(svr); + // }); + // }else{ + // this.visibilityRuleContext.rules.push(rule); + // } - } + // } //removes rule that has the specific id either as a source either as a target - public annihilateId(id: string) : void{ + public removeAllIdReferences(id: string) : void{ + + // * Remove from visibility rues and visibility rules context //remove as a target const temp = this.visibilityRuleContext.rules.map((x,i) => (x.targetControlId === id )? i : null ); @@ -238,10 +308,42 @@ export class VisibilityRulesService { tbd.reverse().forEach(index =>{ this.visibilityRuleContext.rules.splice(index,1); }); + + + + // * Remove from computational map + + // as a target + if(this.elementComputationalMap.get(id)){ + this.elementComputationalMap.delete(id); + } + + + // as a source + const keyIterator = this.elementComputationalMap.keys(); + let currentKey = keyIterator.next(); + + + while(!currentKey.done){ + const currentVals = this.elementComputationalMap.get(currentKey.value); + currentVals.delete(id); + currentKey = keyIterator.next(); + } } public addNewRule(rule: Rule): void{ + const targetId = rule.targetField; + const sourceId = rule.sourceField; + this.visibilityRuleContext.addToVisibilityRulesContext(rule); + + const visibilityMap = this.elementComputationalMap.get(targetId) ? this.elementComputationalMap.get(targetId) : new Map< String, boolean>(); + + visibilityMap.set(sourceId, this.DEFAULTVISIBILITY); + const isVisible = this._computeVisibility(targetId); + + this._emitChangesIfNeeded(targetId, isVisible); + this.elementVisibilityMap.set(targetId, isVisible); } }