|
|
|
@ -1,8 +1,8 @@
|
|
|
|
|
import { ApplicationRef, Injectable, NgZone } from '@angular/core';
|
|
|
|
|
import { AbstractControl, FormArray, FormControl, FormGroup } from '@angular/forms';
|
|
|
|
|
import { AbstractControl, FormArray, FormGroup } from '@angular/forms';
|
|
|
|
|
import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style';
|
|
|
|
|
import { isNumeric } from '@app/utilities/enhancers/utils';
|
|
|
|
|
import { Subject } from 'rxjs';
|
|
|
|
|
import { isNumeric } from 'rxjs/internal/util/isNumeric';
|
|
|
|
|
import { Rule } from '../../../../core/model/dataset-profile-definition/rule';
|
|
|
|
|
import { VisibilityRule } from './models/visibility-rule';
|
|
|
|
|
import { VisibilityRuleSource } from './models/visibility-rule-source';
|
|
|
|
@ -11,13 +11,13 @@ import { VisibilityRulesContext } from './models/visibility-rules-context';
|
|
|
|
|
@Injectable()
|
|
|
|
|
export class VisibilityRulesService {
|
|
|
|
|
|
|
|
|
|
private readonly VISIBILITY_RULE_LOGIC: 'OR'| 'AND' = 'OR';
|
|
|
|
|
private readonly VISIBILITY_RULE_LOGIC: 'OR' | 'AND' = 'OR';
|
|
|
|
|
private readonly DEFAULTVISIBILITY = false;
|
|
|
|
|
|
|
|
|
|
private visibilityRuleContext: VisibilityRulesContext;
|
|
|
|
|
private form: AbstractControl;
|
|
|
|
|
private elementVisibilityMap = new Map<String, boolean>();
|
|
|
|
|
private elementComputationalMap = new Map<String, Map<String,boolean>>(); /// keep saved the values of each form control validity value
|
|
|
|
|
private elementComputationalMap = new Map<String, Map<String, boolean>>(); /// keep saved the values of each form control validity value
|
|
|
|
|
private _changeMade$ = new Subject<void>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -48,17 +48,17 @@ export class VisibilityRulesService {
|
|
|
|
|
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<String, boolean>();
|
|
|
|
|
const visibilityMap = this.elementComputationalMap.get(targetId) ? this.elementComputationalMap.get(targetId) : new Map<String, boolean>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (value instanceof Array){
|
|
|
|
|
if (value instanceof Array) {
|
|
|
|
|
|
|
|
|
|
const parsedSourceControlValues = visibilityRule.sourceVisibilityRules.map(e=>this.parseValue(e.sourceControlValue));
|
|
|
|
|
const parsedValues = value.map(e=>this.parseValue(e));
|
|
|
|
|
const parsedSourceControlValues = visibilityRule.sourceVisibilityRules.map(e => this.parseValue(e.sourceControlValue));
|
|
|
|
|
const parsedValues = value.map(e => this.parseValue(e));
|
|
|
|
|
|
|
|
|
|
const isVisible = parsedValues.map(v => parsedSourceControlValues.includes(v)).reduce((acc, current) => acc || current, false);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
@ -67,16 +67,16 @@ export class VisibilityRulesService {
|
|
|
|
|
visibilityMap.set(sourceId, isVisible);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
const visibilityDependencySource = visibilityRule.sourceVisibilityRules.filter( x=> x.sourceControlId === sourceId);
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
@ -84,10 +84,10 @@ export class VisibilityRulesService {
|
|
|
|
|
const isVisible = this._computeVisibility(targetId);
|
|
|
|
|
this._emitChangesIfNeeded(targetId, isVisible);
|
|
|
|
|
this.elementVisibilityMap.set(targetId, isVisible);
|
|
|
|
|
if(!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))) {
|
|
|
|
@ -106,20 +106,20 @@ export class VisibilityRulesService {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private _computeVisibility(targetId: string) : boolean{
|
|
|
|
|
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){
|
|
|
|
|
while (!currentVal.done) {
|
|
|
|
|
visibilityValues.push(currentVal.value);
|
|
|
|
|
currentVal = values.next();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(visibilityValues.length){
|
|
|
|
|
return visibilityValues.reduce((r, c)=>{
|
|
|
|
|
if(this.VISIBILITY_RULE_LOGIC === 'OR'){
|
|
|
|
|
if (visibilityValues.length) {
|
|
|
|
|
return visibilityValues.reduce((r, c) => {
|
|
|
|
|
if (this.VISIBILITY_RULE_LOGIC === 'OR') {
|
|
|
|
|
return r || c;
|
|
|
|
|
} else {
|
|
|
|
|
return r && c;
|
|
|
|
@ -139,11 +139,11 @@ export class VisibilityRulesService {
|
|
|
|
|
this._changeMade$.next();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private _populateComputationMap(): void{
|
|
|
|
|
this.visibilityRuleContext.rules.forEach(rule =>{
|
|
|
|
|
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 =>{
|
|
|
|
|
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);
|
|
|
|
@ -218,9 +218,9 @@ export class VisibilityRulesService {
|
|
|
|
|
|
|
|
|
|
private resetFieldFormGroup(formGroup: FormGroup) {
|
|
|
|
|
const renderStyle = formGroup.getRawValue().viewStyle.renderStyle;
|
|
|
|
|
if(renderStyle ===DatasetProfileFieldViewStyle.Validation || renderStyle === DatasetProfileFieldViewStyle.DatasetIdentifier){
|
|
|
|
|
formGroup.get('value').setValue({identifier:'',type:'' });
|
|
|
|
|
}else{
|
|
|
|
|
if (renderStyle === DatasetProfileFieldViewStyle.Validation || renderStyle === DatasetProfileFieldViewStyle.DatasetIdentifier) {
|
|
|
|
|
formGroup.get('value').setValue({ identifier: '', type: '' });
|
|
|
|
|
} else {
|
|
|
|
|
formGroup.get('value').setValue(formGroup.get('defaultValue').value ? this.parseValue(formGroup.get('defaultValue').value.value) : undefined);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -232,23 +232,23 @@ export class VisibilityRulesService {
|
|
|
|
|
});
|
|
|
|
|
(formGroup.get('multiplicityItems') as FormArray).controls.splice(0);
|
|
|
|
|
}
|
|
|
|
|
private _emitChangesIfNeeded(id:string, valueToBeSet: boolean){
|
|
|
|
|
if(this.elementVisibilityMap.has(id)){
|
|
|
|
|
if(this.elementVisibilityMap.get(id) != valueToBeSet){
|
|
|
|
|
private _emitChangesIfNeeded(id: string, valueToBeSet: boolean) {
|
|
|
|
|
if (this.elementVisibilityMap.has(id)) {
|
|
|
|
|
if (this.elementVisibilityMap.get(id) != valueToBeSet) {
|
|
|
|
|
this._changeMade$.next();
|
|
|
|
|
}
|
|
|
|
|
}else{
|
|
|
|
|
} else {
|
|
|
|
|
this._changeMade$.next();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public get visibilityChange(){
|
|
|
|
|
public get visibilityChange() {
|
|
|
|
|
return this._changeMade$.asObservable();
|
|
|
|
|
}
|
|
|
|
|
public getVisibilityDependency(targetId: string): VisibilityRuleSource[] | null {
|
|
|
|
|
return this.visibilityRuleContext.rules.reduce((hasDependency, rule)=>{
|
|
|
|
|
if(hasDependency) return hasDependency;
|
|
|
|
|
return this.visibilityRuleContext.rules.reduce((hasDependency, rule) => {
|
|
|
|
|
if (hasDependency) return hasDependency;
|
|
|
|
|
|
|
|
|
|
if(rule.targetControlId === targetId){
|
|
|
|
|
if (rule.targetControlId === targetId) {
|
|
|
|
|
return rule.sourceVisibilityRules;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -256,7 +256,7 @@ export class VisibilityRulesService {
|
|
|
|
|
}, null) as VisibilityRuleSource[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public getVisibilityTargets(sourceId: string) : string[]{
|
|
|
|
|
public getVisibilityTargets(sourceId: string): string[] {
|
|
|
|
|
return this.visibilityRuleContext.rules.filter(x => {
|
|
|
|
|
const result = x.sourceVisibilityRules.filter(y => y.sourceControlId === sourceId);
|
|
|
|
|
return result.length;
|
|
|
|
@ -280,33 +280,33 @@ export class VisibilityRulesService {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//removes rule that has the specific id either as a source either as a target
|
|
|
|
|
public removeAllIdReferences(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 );
|
|
|
|
|
const indexes = temp.filter( x => x !== null);
|
|
|
|
|
const temp = this.visibilityRuleContext.rules.map((x, i) => (x.targetControlId === id) ? i : null);
|
|
|
|
|
const indexes = temp.filter(x => x !== null);
|
|
|
|
|
indexes.reverse().forEach(index => this.visibilityRuleContext.rules.splice(index, 1));
|
|
|
|
|
this.elementVisibilityMap.delete(id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//remove as a source
|
|
|
|
|
const tbd = this.visibilityRuleContext.rules.reduce((to_be_deleted ,rule, ruleIdx) =>{
|
|
|
|
|
const idxs = rule.sourceVisibilityRules.map((x,i) => (x.sourceControlId === id) ? i : null).filter( x=> x !== null );
|
|
|
|
|
idxs.reverse().forEach( index => rule.sourceVisibilityRules.splice(index, 1));
|
|
|
|
|
const tbd = this.visibilityRuleContext.rules.reduce((to_be_deleted, rule, ruleIdx) => {
|
|
|
|
|
const idxs = rule.sourceVisibilityRules.map((x, i) => (x.sourceControlId === id) ? i : null).filter(x => x !== null);
|
|
|
|
|
idxs.reverse().forEach(index => rule.sourceVisibilityRules.splice(index, 1));
|
|
|
|
|
|
|
|
|
|
if(!rule.sourceVisibilityRules.length){
|
|
|
|
|
if (!rule.sourceVisibilityRules.length) {
|
|
|
|
|
to_be_deleted.push(ruleIdx);
|
|
|
|
|
}
|
|
|
|
|
return to_be_deleted
|
|
|
|
|
},[]);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//clean up empty
|
|
|
|
|
tbd.reverse().forEach(index =>{
|
|
|
|
|
this.visibilityRuleContext.rules.splice(index,1);
|
|
|
|
|
tbd.reverse().forEach(index => {
|
|
|
|
|
this.visibilityRuleContext.rules.splice(index, 1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -314,7 +314,7 @@ export class VisibilityRulesService {
|
|
|
|
|
// * Remove from computational map
|
|
|
|
|
|
|
|
|
|
// as a target
|
|
|
|
|
if(this.elementComputationalMap.get(id)){
|
|
|
|
|
if (this.elementComputationalMap.get(id)) {
|
|
|
|
|
this.elementComputationalMap.delete(id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -323,8 +323,8 @@ export class VisibilityRulesService {
|
|
|
|
|
const keyIterator = this.elementComputationalMap.keys();
|
|
|
|
|
let currentKey = keyIterator.next();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while(!currentKey.done){
|
|
|
|
|
|
|
|
|
|
while (!currentKey.done) {
|
|
|
|
|
const currentVals = this.elementComputationalMap.get(currentKey.value);
|
|
|
|
|
currentVals.delete(id);
|
|
|
|
|
currentKey = keyIterator.next();
|
|
|
|
@ -332,15 +332,15 @@ export class VisibilityRulesService {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public addNewRule(rule: Rule): void{
|
|
|
|
|
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>();
|
|
|
|
|
const visibilityMap = this.elementComputationalMap.get(targetId) ? this.elementComputationalMap.get(targetId) : new Map<String, boolean>();
|
|
|
|
|
|
|
|
|
|
visibilityMap.set(sourceId, this.DEFAULTVISIBILITY);
|
|
|
|
|
visibilityMap.set(sourceId, this.DEFAULTVISIBILITY);
|
|
|
|
|
const isVisible = this._computeVisibility(targetId);
|
|
|
|
|
|
|
|
|
|
this._emitChangesIfNeeded(targetId, isVisible);
|
|
|
|
|