import { AfterViewInit, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; import {EnvProperties} from '../../../openaireLibrary/utils/properties/env-properties'; import {Constraint, Criteria, SelectionCriteria} from '../../../openaireLibrary/utils/entities/contentProvider'; import {AbstractControl, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup, Validators} from '@angular/forms'; import {properties} from "../../../../environments/environment"; import {MatSlideToggleChange} from "@angular/material/slide-toggle"; import {HelperFunctions} from "../../../openaireLibrary/utils/HelperFunctions.class"; import {CriteriaUtils} from "../criteria-utils"; import {NotificationHandler} from "../../../openaireLibrary/utils/notification-handler"; import {OpenaireEntities} from "../../../openaireLibrary/utils/properties/searchFields"; import {ISVocabulariesService} from "../../../openaireLibrary/utils/staticAutoComplete/ISVocabularies.service"; import {Subscription} from "rxjs"; @Component({ selector: 'criteria', templateUrl: 'criteria.component.html', styleUrls: ['criteria.component.less'] }) export class CriteriaComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy { @Input() public entityType: string = 'filter'; @Input() public entityTypePlural: string = 'filters'; @Input() public selectionCriteria: SelectionCriteria; @Input() public height: number = 0; public criteriaHeight: number = 0; public selectionCriteriaForm: UntypedFormGroup; public properties: EnvProperties = properties; public criteriaUtils: CriteriaUtils = new CriteriaUtils(); public fos: string[] = []; public sdg: string[] = []; public loading = true; public openaireEntities = OpenaireEntities; private subscriptions: any[] = []; constructor(private cdr: ChangeDetectorRef, private vocabulariesService: ISVocabulariesService, private fb: UntypedFormBuilder) { } ngOnInit() { this.loading = false; this.subscriptions.push(this.vocabulariesService.getVocabularyByType('fos', null, properties).subscribe((fos: any[]) => { this.fos = fos.map(element => element.id); })); this.subscriptions.push(this.vocabulariesService.getVocabularyByType('sdg', null, properties).subscribe((sdg: any[]) => { this.sdg = sdg.map(element => element.id); })); } ngOnChanges(changes: SimpleChanges) { if(changes.selectionCriteria){ this.reset(); } this.calculateMaxHeight(); } ngAfterViewInit() { this.calculateMaxHeight(); } ngOnDestroy() { this.subscriptions.forEach(subscription => { if (subscription instanceof Subscription) { subscription.unsubscribe(); } }); } calculateMaxHeight() { if(this.height) { if(this.height > 0) { /* Element height - margins(20 + 20) - button height(42) */ this.criteriaHeight = this.height - 40 - 42; this.cdr.detectChanges(); } } } reset() { this.selectionCriteriaForm = this.fb.group({ criteria: this.fb.array([]) }); if (this.selectionCriteria?.criteria) { this.selectionCriteria.criteria.forEach(criterion => { let constraintArray: UntypedFormArray = this.fb.array([]); criterion.constraint.forEach(constraint => { constraintArray.push(this.fb.group({ field: this.fb.control(constraint.field, Validators.required), verb: this.fb.control(this.removeSuffix(constraint.verb), Validators.required), value: this.fb.control(constraint.value, Validators.required), verb_suffix: this.fb.control(this.getSuffix(constraint.verb)) })); }); this.criteria.push(this.fb.group({ constraint: constraintArray })); }); } } get disabled() { return this.loading || !this.dirty || this.selectionCriteriaForm.invalid; } public get criteria(): UntypedFormArray { return this.selectionCriteriaForm.get('criteria') as UntypedFormArray; } public getConstraint(i: number): UntypedFormArray { return this.criteria.at(i).get('constraint') as UntypedFormArray; } public addCriteria() { let constraintArray: UntypedFormArray = this.fb.array([ this.fb.group({ field: this.fb.control('', Validators.required), verb: this.fb.control('contains', Validators.required), value: this.fb.control('', Validators.required), verb_suffix: this.fb.control('_caseinsensitive') }) ]); this.criteria.push(this.fb.group({constraint: constraintArray})); this.cdr.detectChanges(); document.getElementById('criterion-' + (this.criteria.length - 1).toString()).scrollIntoView({behavior: 'smooth'}); } public addConstraint(i: number) { let constraintArray: UntypedFormArray = this.criteria.at(i).get('constraint') as UntypedFormArray; constraintArray.push(this.fb.group({ field: this.fb.control('', Validators.required), verb: this.fb.control('contains', Validators.required), value: this.fb.control('', Validators.required), verb_suffix: this.fb.control('_caseinsensitive') })); this.cdr.detectChanges(); } public removeConstraint(i: number, j: number) { let constraintArray: UntypedFormArray = this.criteria.at(i).get('constraint') as UntypedFormArray; constraintArray.removeAt(j); if (constraintArray.length === 0) { this.criteria.removeAt(i); } this.cdr.detectChanges(); } get criteriaArray(): Criteria[] { return (this.selectionCriteria?.criteria) ? this.selectionCriteria?.criteria : []; } get dirty() { if (!this.selectionCriteria || !this.criteria) { return false; } else if (this.criteria.length !== this.criteriaArray.length) { return true; } else { return this.criteriaArray.filter((criterion, i) => { if (criterion.constraint.length !== this.getConstraint(i).length) { return true; } else { let temp = this.getConstraint(i).value; return criterion.constraint.filter((constraint, j) => { return constraint.field !== temp[j].field || constraint.verb !== (temp[j].verb + temp[j].verb_suffix) || constraint.value !== temp[j].value; }).length > 0; } }).length > 0; } } save(callback: (selectionCriteria) => void = null) { if (this.selectionCriteriaForm.valid) { this.loading = true; callback(this.parseForm(this.selectionCriteriaForm.value)); } } handeError(message, error = null) { console.error(error); NotificationHandler.rise(message, 'danger'); } caseSensitive(event: MatSlideToggleChange, constraint: AbstractControl) { if (event.checked) { constraint.get('verb_suffix').setValue(''); } else { constraint.get('verb_suffix').setValue('_caseinsensitive'); } } removeSuffix(verb: string) { return verb.replace('_caseinsensitive', ''); } getSuffix(verb: string) { if (verb.includes('_caseinsensitive')) { return '_caseinsensitive'; } else { return ''; } } parseForm(formValue): SelectionCriteria { let value = HelperFunctions.copy(formValue); let selectionCriteria: SelectionCriteria = new SelectionCriteria(); selectionCriteria.criteria = []; value.criteria.forEach(criterion => { let criteria = new Criteria(); criteria.constraint = []; criterion.constraint.forEach(constraint => { criteria.constraint.push(new Constraint(constraint.verb + constraint.verb_suffix, constraint.field, constraint.value)); }); selectionCriteria.criteria.push(criteria); }) return selectionCriteria; } }