visibiliity service performance improvements

This commit is contained in:
Diamantis Tziotzios 2022-02-03 20:06:27 +02:00
parent 048189952c
commit 85859ce078
6 changed files with 232 additions and 166 deletions

View File

@ -1,15 +1,17 @@
import { Component, Input, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core';
import { FormArray, FormGroup, AbstractControl, FormArrayName } from '@angular/forms'; import { FormArray, FormGroup } from '@angular/forms';
import { DatasetDescriptionCompositeFieldEditorModel, DatasetDescriptionFieldEditorModel } from '../../dataset-description-form.model'; import { BaseComponent } from '@common/base/base.component';
import { takeUntil } from 'rxjs/operators';
import { ToCEntry } from '../../dataset-description.component'; import { ToCEntry } from '../../dataset-description.component';
import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service'; import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service';
@Component({ @Component({
selector: 'app-form-composite-field', selector: 'app-form-composite-field',
templateUrl: './form-composite-field.component.html', templateUrl: './form-composite-field.component.html',
styleUrls: ['./form-composite-field.component.scss'] styleUrls: ['./form-composite-field.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FormCompositeFieldComponent { export class FormCompositeFieldComponent extends BaseComponent {
@Input() datasetProfileId: String; @Input() datasetProfileId: String;
@Input() form: FormGroup; @Input() form: FormGroup;
@ -19,8 +21,13 @@ export class FormCompositeFieldComponent {
constructor( constructor(
public visibilityRulesService: VisibilityRulesService, public visibilityRulesService: VisibilityRulesService,
private changeDetector: ChangeDetectorRef
//private markForConsiderationService: MarkForConsiderationService, //private markForConsiderationService: MarkForConsiderationService,
) { ) {
super();
this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
this.changeDetector.markForCheck();
});
} }
ngOnInit() { ngOnInit() {

View File

@ -1,5 +1,5 @@
<div *ngIf="form && this.visibilityRulesService.checkElementVisibility(this.form.get('id').value)" [id]="this.form.get('id').value" <div *ngIf="form && visible" [id]="this.form.get('id').value"
[formGroup]="form" [ngSwitch]="this.form.get('viewStyle').value.renderStyle" class="dynamic-form-field row"> [formGroup]="form" [ngSwitch]="renderStyle" class="dynamic-form-field row">
<h5 *ngIf="this.form.get('title').value && !isChild">{{this.form.get('title').value}}</h5> <h5 *ngIf="this.form.get('title').value && !isChild">{{this.form.get('title').value}}</h5>
<mat-icon *ngIf="this.form.get('additionalInformation').value && !isChild" matTooltip="{{this.form.get('additionalInformation').value}}">info</mat-icon> <mat-icon *ngIf="this.form.get('additionalInformation').value && !isChild" matTooltip="{{this.form.get('additionalInformation').value}}">info</mat-icon>

View File

@ -1,5 +1,5 @@
import { Component, Input, OnInit } from '@angular/core'; import { ChangeDetectionStrategy, Component, Input, OnInit, SimpleChanges } from '@angular/core';
import { FormGroup, FormArray, FormControl } from '@angular/forms'; import { FormGroup, FormArray, FormControl } from '@angular/forms';
import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type'; import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type';
import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style'; import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style';
@ -19,7 +19,7 @@ import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/sing
import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service';
import { BaseComponent } from '@common/base/base.component'; import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { map, takeUntil } from 'rxjs/operators'; import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item'; import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item';
import { ExternalDatasetCriteria } from '@app/core/query/external-dataset/external-dataset-criteria'; import { ExternalDatasetCriteria } from '@app/core/query/external-dataset/external-dataset-criteria';
@ -39,7 +39,8 @@ import { AutoCompleteSingleData } from '@app/core/model/dataset-profile-definiti
@Component({ @Component({
selector: 'app-form-field', selector: 'app-form-field',
templateUrl: './form-field.component.html', templateUrl: './form-field.component.html',
styleUrls: ['./form-field.component.scss'] styleUrls: ['./form-field.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FormFieldComponent extends BaseComponent implements OnInit { export class FormFieldComponent extends BaseComponent implements OnInit {
@ -49,6 +50,14 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
@Input() isChild: Boolean = false; @Input() isChild: Boolean = false;
@Input() autocompleteOptions: AutoCompleteSingleData; @Input() autocompleteOptions: AutoCompleteSingleData;
visible: boolean = true;
_renderStyle: DatasetProfileFieldViewStyle = null;
get renderStyle() {
//console.log('renderStyle');
return this._renderStyle;
}
// change: Subscription; // change: Subscription;
// trackByFn = (index, item) => item ? item['id'] : null; // trackByFn = (index, item) => item ? item['id'] : null;
@ -95,9 +104,22 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
private datasetService: DatasetService, private datasetService: DatasetService,
private dmpService: DmpService, private dmpService: DmpService,
private currencyService: CurrencyService private currencyService: CurrencyService
) { super(); } ) {
super();
this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
this.visible = this.visibilityRulesService.checkElementVisibility(this.form?.get('id')?.value);
});
}
ngOnChanges(changes: SimpleChanges) {
if (changes['form']) {
this._renderStyle = this.form.get('viewStyle')?.value?.renderStyle;
}
}
ngOnInit() { ngOnInit() {
if (this.form.get('value').value) { if (this.form.get('value').value) {
this.visibilityRulesService.updateValueAndVisibility(this.form.get('id').value, this.form.get('value').value); this.visibilityRulesService.updateValueAndVisibility(this.form.get('id').value, this.form.get('value').value);
} }
@ -253,7 +275,10 @@ export class FormFieldComponent extends BaseComponent implements OnInit {
// this.form = this.visibilityRulesService.getFormGroup(this.field.id); // this.form = this.visibilityRulesService.getFormGroup(this.field.id);
this.form.get('value').valueChanges this.form.get('value').valueChanges
.pipe(takeUntil(this._destroyed)) .pipe(
takeUntil(this._destroyed),
distinctUntilChanged()
)
.subscribe(item => { .subscribe(item => {
// if (this.form.get('viewStyle').value.renderStyle === DatasetProfileFieldViewStyle.ComboBox && this.form.get('data').value.type === DatasetProfileComboBoxType.WordList && this.form.get('data').value.multiList) { // if (this.form.get('viewStyle').value.renderStyle === DatasetProfileFieldViewStyle.ComboBox && this.form.get('data').value.type === DatasetProfileComboBoxType.WordList && this.form.get('data').value.multiList) {
// item.forEach(element => { // item.forEach(element => {

View File

@ -1,17 +1,19 @@
import { AfterViewInit, Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
import { FormGroup, FormArray, AbstractControl } from '@angular/forms'; import { FormArray, FormGroup } from '@angular/forms';
import { BaseComponent } from '@common/base/base.component';
import { takeUntil } from 'rxjs/operators';
import { DatasetDescriptionCompositeFieldEditorModel } from '../../../dataset-description-form.model';
import { FormFocusService } from '../../../form-focus/form-focus.service'; import { FormFocusService } from '../../../form-focus/form-focus.service';
import { VisibilityRulesService } from '../../../visibility-rules/visibility-rules.service';
import { DatasetDescriptionSectionEditorModel, DatasetDescriptionCompositeFieldEditorModel } from '../../../dataset-description-form.model';
import { FormCompositeFieldComponent } from '../../form-composite-field/form-composite-field.component';
import { LinkToScroll } from '../../../tableOfContentsMaterial/table-of-contents'; import { LinkToScroll } from '../../../tableOfContentsMaterial/table-of-contents';
import { VisibilityRulesService } from '../../../visibility-rules/visibility-rules.service';
@Component({ @Component({
selector: 'app-form-section-inner', selector: 'app-form-section-inner',
templateUrl: './form-section-inner.component.html', templateUrl: './form-section-inner.component.html',
styleUrls: ['./form-section-inner.component.scss'] styleUrls: ['./form-section-inner.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FormSectionInnerComponent implements OnInit, OnChanges { export class FormSectionInnerComponent extends BaseComponent implements OnInit, OnChanges {
//@Input() section: DatasetDescriptionSectionEditorModel; //@Input() section: DatasetDescriptionSectionEditorModel;
@Input() datasetProfileId: String; @Input() datasetProfileId: String;
@ -28,8 +30,14 @@ export class FormSectionInnerComponent implements OnInit, OnChanges {
constructor( constructor(
public visibilityRulesService: VisibilityRulesService, public visibilityRulesService: VisibilityRulesService,
private changeDetector: ChangeDetectorRef,
private formFocusService: FormFocusService private formFocusService: FormFocusService
) { } ) {
super();
this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
this.changeDetector.markForCheck();
});
}
ngOnInit() { ngOnInit() {
// if (this.section) { // if (this.section) {

View File

@ -1,22 +1,23 @@
import { AfterViewInit, Component, Input, OnInit, OnChanges, SimpleChanges, Output, EventEmitter } from '@angular/core'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
import { FormGroup, FormArray, AbstractControl } from '@angular/forms'; import { FormArray, FormGroup } from '@angular/forms';
import { FormFocusService } from '../../form-focus/form-focus.service';
import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service';
import { DatasetDescriptionSectionEditorModel, DatasetDescriptionCompositeFieldEditorModel } from '../../dataset-description-form.model';
import { FormCompositeFieldComponent } from '../form-composite-field/form-composite-field.component';
import { LinkToScroll } from '../../tableOfContentsMaterial/table-of-contents';
import { ToCEntry, ToCEntryType } from '../../dataset-description.component';
import { VisibilityRuleSource } from '../../visibility-rules/models/visibility-rule-source';
import { VisibilityRule } from '../../visibility-rules/models/visibility-rule';
import { Rule } from '@app/core/model/dataset-profile-definition/rule'; import { Rule } from '@app/core/model/dataset-profile-definition/rule';
import { BaseComponent } from '@common/base/base.component';
import { takeUntil } from 'rxjs/operators';
import { DatasetDescriptionCompositeFieldEditorModel } from '../../dataset-description-form.model';
import { ToCEntry, ToCEntryType } from '../../dataset-description.component';
import { FormFocusService } from '../../form-focus/form-focus.service';
import { LinkToScroll } from '../../tableOfContentsMaterial/table-of-contents';
import { VisibilityRuleSource } from '../../visibility-rules/models/visibility-rule-source';
import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service';
@Component({ @Component({
selector: 'app-form-section', selector: 'app-form-section',
templateUrl: './form-section.component.html', templateUrl: './form-section.component.html',
styleUrls: ['./form-section.component.scss'] styleUrls: ['./form-section.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class FormSectionComponent implements OnInit, OnChanges { export class FormSectionComponent extends BaseComponent implements OnInit, OnChanges {
//@Input() section: DatasetDescriptionSectionEditorModel; //@Input() section: DatasetDescriptionSectionEditorModel;
@Input() datasetProfileId: String; @Input() datasetProfileId: String;
@ -39,8 +40,14 @@ export class FormSectionComponent implements OnInit, OnChanges {
constructor( constructor(
public visibilityRulesService: VisibilityRulesService, public visibilityRulesService: VisibilityRulesService,
private formFocusService: FormFocusService private formFocusService: FormFocusService,
) { } private changeDetector: ChangeDetectorRef
) {
super();
this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
this.changeDetector.markForCheck();
});
}
ngOnInit() { ngOnInit() {
// if (this.section) { // if (this.section) {

View File

@ -2,7 +2,7 @@ import { ApplicationRef, Injectable, NgZone } from '@angular/core';
import { AbstractControl, FormArray, FormGroup } from '@angular/forms'; import { AbstractControl, FormArray, FormGroup } from '@angular/forms';
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 { isNumeric } from '@app/utilities/enhancers/utils'; import { isNumeric } from '@app/utilities/enhancers/utils';
import { Subject } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { Rule } from '../../../../core/model/dataset-profile-definition/rule'; import { Rule } from '../../../../core/model/dataset-profile-definition/rule';
import { VisibilityRule } from './models/visibility-rule'; import { VisibilityRule } from './models/visibility-rule';
import { VisibilityRuleSource } from './models/visibility-rule-source'; import { VisibilityRuleSource } from './models/visibility-rule-source';
@ -16,7 +16,8 @@ export class VisibilityRulesService {
private visibilityRuleContext: VisibilityRulesContext; private visibilityRuleContext: VisibilityRulesContext;
private form: AbstractControl; private form: AbstractControl;
private elementVisibilityMap = new Map<String, boolean>(); public elementVisibilityMap = new Map<String, boolean>();
private elementVisibilityMapSubject = new Subject<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>(); private _changeMade$ = new Subject<void>();
@ -28,6 +29,10 @@ export class VisibilityRulesService {
} }
getElementVisibilityMapObservable(): Observable<Map<String, boolean>> {
return this.elementVisibilityMapSubject.asObservable();
}
public checkElementVisibility(id: string): boolean { public checkElementVisibility(id: string): boolean {
if (this.visibilityRuleContext.rules.filter(item => item.targetControlId === id).length === 0) { return true; } if (this.visibilityRuleContext.rules.filter(item => item.targetControlId === id).length === 0) { return true; }
return this.elementVisibilityMap.has(id) ? this.elementVisibilityMap.get(id) : false; return this.elementVisibilityMap.has(id) ? this.elementVisibilityMap.get(id) : false;
@ -41,8 +46,12 @@ export class VisibilityRulesService {
} }
public updateValueAndVisibility(id: string, value: any) { public updateValueAndVisibility(id: string, value: any) {
console.log('updateValueAndVisibility');
const visibilityRules = this.visibilityRuleContext.rules.filter(item => item.sourceVisibilityRules.filter(source => source.sourceControlId === id).length > 0); const visibilityRules = this.visibilityRuleContext.rules.filter(item => item.sourceVisibilityRules.filter(source => source.sourceControlId === id).length > 0);
if (visibilityRules.length > 0) {
visibilityRules.forEach(item => this.evaluateVisibility(item, value, id)); visibilityRules.forEach(item => this.evaluateVisibility(item, value, id));
this.elementVisibilityMapSubject.next(this.elementVisibilityMap);
}
} }
private evaluateVisibility(visibilityRule: VisibilityRule, value: any, sourceId: string) {// source controlId is the same private evaluateVisibility(visibilityRule: VisibilityRule, value: any, sourceId: string) {// source controlId is the same
@ -84,8 +93,10 @@ export class VisibilityRulesService {
const isVisible = this._computeVisibility(targetId); const isVisible = this._computeVisibility(targetId);
this._emitChangesIfNeeded(targetId, isVisible); this._emitChangesIfNeeded(targetId, isVisible);
const previousVisibility = this.elementVisibilityMap.get(targetId);
this.elementVisibilityMap.set(targetId, isVisible); this.elementVisibilityMap.set(targetId, isVisible);
if (!isVisible) {
if (!isVisible && previousVisibility !== isVisible) {
this.resetControlWithId(this.form, targetId); this.resetControlWithId(this.form, targetId);
} }
@ -220,11 +231,18 @@ export class VisibilityRulesService {
private resetFieldFormGroup(formGroup: FormGroup) { private resetFieldFormGroup(formGroup: FormGroup) {
const renderStyle = formGroup.getRawValue().viewStyle.renderStyle; const renderStyle = formGroup.getRawValue().viewStyle.renderStyle;
if (renderStyle === DatasetProfileFieldViewStyle.Validation || renderStyle === DatasetProfileFieldViewStyle.DatasetIdentifier) { if (renderStyle === DatasetProfileFieldViewStyle.Validation || renderStyle === DatasetProfileFieldViewStyle.DatasetIdentifier) {
formGroup.get('value').setValue({ identifier: '', type: '' }); const value = { identifier: '', type: '' };
} else { if (formGroup.get('value').value != value) {
formGroup.get('value').setValue(formGroup.get('defaultValue').value ? this.parseValue(formGroup.get('defaultValue').value.value) : undefined); formGroup.get('value').setValue(value, { emitEvent: false });
this.updateValueAndVisibility(formGroup.get('id').value, value);
}
} else {
const value = formGroup.get('defaultValue').value ? this.parseValue(formGroup.get('defaultValue').value.value) : undefined;
if (formGroup.get('value').value != value) {
formGroup.get('value').setValue(value, { emitEvent: false });
this.updateValueAndVisibility(formGroup.get('id').value, value);
}
} }
} }
private resetCompositeFieldFormGroup(formGroup: FormGroup) { private resetCompositeFieldFormGroup(formGroup: FormGroup) {
@ -352,6 +370,7 @@ export class VisibilityRulesService {
this._emitChangesIfNeeded(targetId, isVisible); this._emitChangesIfNeeded(targetId, isVisible);
this.elementVisibilityMap.set(targetId, isVisible); this.elementVisibilityMap.set(targetId, isVisible);
this.elementVisibilityMapSubject.next(this.elementVisibilityMap);
} }