mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merged PR 693: Fix Reading Age Filter and Added Error Message
Fix Reading Age Filter and Added Error Message
This commit is contained in:
committed by
Lorenz Hilpert
parent
751a175673
commit
58536ef3f7
@@ -1,7 +1,8 @@
|
||||
import { StringDictionary } from '@cmf/core';
|
||||
import { InputGroupDTO, InputDTO, OptionDTO, InputType } from '@swagger/cat';
|
||||
import { SelectFilterGroup, SelectFilter, SelectFilterOption, FilterType, Filter, FilterOption, RangeFilter } from '@ui/filter';
|
||||
import { InputDTO, OptionDTO, InputType } from '@swagger/cat';
|
||||
import { SelectFilter, SelectFilterOption, FilterType, Filter, FilterOption, RangeFilter } from '@ui/filter';
|
||||
import { RangeFilterOption } from 'apps/ui/filter/src/lib/models/range-filter-option';
|
||||
import { isRangeFilterOption, isSelectFilterOption } from 'apps/ui/filter/src/lib/type-guards';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
export function fromInputDto(input: InputDTO): Filter {
|
||||
@@ -100,9 +101,17 @@ export function mapSelectedFilterToParams(source: Filter[]): string {
|
||||
const dict: StringDictionary<string> = {};
|
||||
for (const filter of source) {
|
||||
const options: FilterOption[] = filter.options;
|
||||
const selected = options.filter((o) => o.selected);
|
||||
// TODO: Start und Stop values bei range-filter mit in die Params
|
||||
// console.log(selected);
|
||||
const selected = options.filter((o) => o.type === 'select' && o.selected);
|
||||
const integerRange = options.filter((o) => o.type === 'integer-range' && o.selected);
|
||||
if (integerRange.length > 0) {
|
||||
dict[filter.key] = integerRange
|
||||
.map((o) => {
|
||||
if (isRangeFilterOption(o)) {
|
||||
return o.id + '-' + o.value;
|
||||
}
|
||||
})
|
||||
.join(';');
|
||||
}
|
||||
if (selected.length > 0) {
|
||||
dict[filter.key] = selected.map((o) => o.id).join(';');
|
||||
}
|
||||
@@ -117,11 +126,19 @@ export function mapSelectedParamsToFilter(params: string, defaultFilters: Filter
|
||||
// ist der selectedFilter ein leerstring ist dann sind alle Filter nicht selected
|
||||
if (params != undefined) {
|
||||
filters?.forEach((filter) => {
|
||||
filter?.options?.forEach((option) => {
|
||||
option.selected = keys.includes(String(option.id));
|
||||
filter?.options?.forEach((option: FilterOption) => {
|
||||
if (isSelectFilterOption(option)) {
|
||||
option.selected = keys.includes(String(option.id));
|
||||
}
|
||||
if (isRangeFilterOption(option)) {
|
||||
const valueAndNumber = keys.find((key) => key?.startsWith(String(option.id)))?.split('-');
|
||||
if (valueAndNumber) {
|
||||
option.selected = true;
|
||||
option.value = valueAndNumber[1];
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return filters;
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from './range-filter.component';
|
||||
export * from './range-filter.validator';
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<div #selectFilter class="isa-card">
|
||||
<div class="select-filter-options isa-mt-10">
|
||||
<div class="isa-mt-10">
|
||||
<p class="range-filter-headline">{{ filter.description }}</p>
|
||||
<div [formGroup]="formGroup" class="range-input-wrapper">
|
||||
<input
|
||||
class="range-filter-input"
|
||||
uiInput
|
||||
type="string"
|
||||
[tabindex]="0"
|
||||
[tabindex]="1"
|
||||
[formControlName]="'start'"
|
||||
[placeholder]="filter.options[0].name"
|
||||
/>
|
||||
@@ -19,5 +19,8 @@
|
||||
[placeholder]="filter.options[1].name"
|
||||
/>
|
||||
</div>
|
||||
<p *ngIf="error" class="range-filter-error">
|
||||
„Von“ darf maximal so groß sein wie „bis“
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
.select-filter-options {
|
||||
@apply pr-px-50;
|
||||
}
|
||||
|
||||
.range-filter-headline {
|
||||
@apply font-semibold text-base;
|
||||
}
|
||||
@@ -20,3 +16,8 @@
|
||||
.range-filter-input::placeholder {
|
||||
@apply font-bold text-xl text-cool-grey;
|
||||
}
|
||||
|
||||
.range-filter-error {
|
||||
@apply font-semibold text-base;
|
||||
color: #f70400;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import { Component, ChangeDetectionStrategy, Input, ElementRef, ChangeDetectorRef, OnInit, Output, EventEmitter } from '@angular/core';
|
||||
import { AbstractControl, FormBuilder, FormGroup, ValidationErrors } from '@angular/forms';
|
||||
import { RangeFilter, RangeFilterOption, SelectFilter } from '../../../models';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { RangeFilter, SelectFilter } from '../../../models';
|
||||
import { isRangeFilter } from '../../../type-guards';
|
||||
import { FilterGroup } from '../../filter-group';
|
||||
import { startValidator, stopValidator } from './range-filter.validator';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-range-filter',
|
||||
@@ -21,82 +23,37 @@ export class UiRangeFilterComponent implements OnInit {
|
||||
|
||||
formGroup: FormGroup;
|
||||
|
||||
startValidator = (opt: RangeFilterOption) => (control: AbstractControl): null | ValidationErrors => {
|
||||
const stopCtrl = control?.parent?.get('stop');
|
||||
if (control.value !== opt.value) {
|
||||
this.updateValue(control.value, opt, control, { compareControlValue: stopCtrl.value, target: 'stop' });
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
stopValidator = (opt: RangeFilterOption) => (control: AbstractControl): null | ValidationErrors => {
|
||||
const startCtrl = control?.parent?.get('start');
|
||||
if (control.value !== opt.value) {
|
||||
this.updateValue(control.value, opt, control, { compareControlValue: startCtrl.value, target: 'start' });
|
||||
}
|
||||
return null;
|
||||
};
|
||||
error: boolean;
|
||||
|
||||
constructor(protected cdr: ChangeDetectorRef, public filterGroup: FilterGroup, private fb: FormBuilder) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.formGroup = this.fb.group({
|
||||
start: this.fb.control(this.filter.options[0].value, [this.startValidator(this.filter.options[0])]),
|
||||
stop: this.fb.control(this.filter.options[1].value, [this.stopValidator(this.filter.options[1])]),
|
||||
start: this.fb.control(this.filter.options[0].value, [startValidator(this.filter, this.filterGroup, this.preSelectCategory)]),
|
||||
stop: this.fb.control(this.filter.options[1].value, [stopValidator(this.filter, this.filterGroup, this.preSelectCategory)]),
|
||||
});
|
||||
this.updateControl();
|
||||
this.filterGroup.updateView.subscribe((_) => {
|
||||
this.updateControl();
|
||||
this.cdr.markForCheck();
|
||||
});
|
||||
|
||||
this.filterGroup.updateView.subscribe((_) => this.cdr.markForCheck());
|
||||
}
|
||||
|
||||
updateValue(
|
||||
value: string,
|
||||
option: RangeFilterOption,
|
||||
control: AbstractControl,
|
||||
compareValue: { compareControlValue: string; target: 'start' | 'stop' }
|
||||
) {
|
||||
value?.length > 0 ? (option.selected = true) : (option.selected = false);
|
||||
option.value = this.checkValue(value, option, compareValue);
|
||||
this.updateControl(option.value, control);
|
||||
this.filterGroup.toggleOption(this.filter, option);
|
||||
this.preSelectCategory(this.filter);
|
||||
this.cdr.markForCheck();
|
||||
// Correctly Update Input Field Values on open Filter Overlay and on Filter Reset
|
||||
updateControl() {
|
||||
const readingAgeFilter = this.filterGroup.value.find((filter) => filter.key === 'reading-age');
|
||||
if (isRangeFilter(readingAgeFilter)) {
|
||||
if (this.formGroup.get('start').hasError('valueRange') || this.formGroup.get('stop').hasError('valueRange')) {
|
||||
this.error = true;
|
||||
} else {
|
||||
this.error = false;
|
||||
}
|
||||
this.formGroup.get('start').setValue(readingAgeFilter.options[0].value);
|
||||
this.formGroup.get('stop').setValue(readingAgeFilter.options[1].value);
|
||||
}
|
||||
}
|
||||
|
||||
updateControl(value: string, control: AbstractControl) {
|
||||
control.setValue(value, { emitEvent: false });
|
||||
}
|
||||
|
||||
checkValue(value: string, option: RangeFilterOption, compareValue: { compareControlValue: string; target: 'start' | 'stop' }): string {
|
||||
let validatedResult =
|
||||
Number(value) <= Number(option.maxValue) && Number(value) >= Number(option.minValue)
|
||||
? value
|
||||
.replace(/[^0-9.]/g, '') // Only Numbers
|
||||
.replace(/^(?:0+(?=[1-9])|0+(?=0$))/gm, '') // No leading Zeros and only one Zero allowed
|
||||
.replace(/(\..*)\./g, '$1') // No special characters
|
||||
: Number(value) > Number(option.maxValue)
|
||||
? option.maxValue
|
||||
: Number(value) < Number(option.minValue)
|
||||
? option.minValue
|
||||
: '';
|
||||
|
||||
// Checking if start value is smaller than stop value
|
||||
// if (compareValue.target === 'stop' && compareValue.compareControlValue !== '') {
|
||||
// if (Number(compareValue.compareControlValue) < Number(validatedResult)) {
|
||||
// validatedResult = compareValue.compareControlValue;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Checking if start value is smaller than stop value and vice versa
|
||||
// if (compareValue.target === 'start' && compareValue.compareControlValue !== '') {
|
||||
// if (Number(compareValue.compareControlValue) > Number(validatedResult)) {
|
||||
// // validatedResult = compareValue.compareControlValue;
|
||||
// }
|
||||
// }
|
||||
|
||||
return validatedResult;
|
||||
}
|
||||
|
||||
preSelectCategory(category: SelectFilter | RangeFilter) {
|
||||
this.category.emit(category);
|
||||
}
|
||||
private preSelectCategory = () => {
|
||||
this.category.emit(this.filter);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import { AbstractControl, ValidationErrors } from '@angular/forms';
|
||||
import { RangeFilter, RangeFilterOption } from '../../../models';
|
||||
import { FilterGroup } from '../../filter-group';
|
||||
|
||||
export function startValidator(filter: RangeFilter, filterGroup: FilterGroup, preSelectCategory: () => void) {
|
||||
return (control: AbstractControl): null | ValidationErrors => {
|
||||
const startOption: RangeFilterOption = filter.options[0];
|
||||
if (control.value !== startOption.value) {
|
||||
preSelectCategory();
|
||||
validateAndSetInput(control, startOption);
|
||||
const compare = compareWithStopValue(startOption.value, control);
|
||||
if (compare.error) {
|
||||
startOption.value = compare.value;
|
||||
filterGroup.setRangeOption(filter, startOption);
|
||||
return { valueRange: 'error' };
|
||||
} else {
|
||||
filterGroup.setRangeOption(filter, startOption);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
export function stopValidator(filter: RangeFilter, filterGroup: FilterGroup, preSelectCategory: () => void) {
|
||||
return (control: AbstractControl): null | ValidationErrors => {
|
||||
const stopOption: RangeFilterOption = filter.options[1];
|
||||
if (control.value !== stopOption.value) {
|
||||
preSelectCategory();
|
||||
validateAndSetInput(control, stopOption);
|
||||
filterGroup.setRangeOption(filter, stopOption);
|
||||
|
||||
const compare = compareWithStartValue(stopOption.value, control);
|
||||
if (compare.error) {
|
||||
control?.parent?.get('start')?.setValue('');
|
||||
return { valueRange: 'error' };
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
function validateAndSetInput(control: AbstractControl, option: RangeFilterOption) {
|
||||
control?.value?.length > 0 ? (option.selected = true) : (option.selected = false);
|
||||
option.value = checkValue(control, option);
|
||||
}
|
||||
|
||||
function checkValue(control: AbstractControl, option: RangeFilterOption): string {
|
||||
let validatedResult = control.value;
|
||||
validatedResult = checkFormat(validatedResult);
|
||||
validatedResult = checkBoundaries(validatedResult, option);
|
||||
return validatedResult;
|
||||
}
|
||||
|
||||
function checkFormat(value: string): string {
|
||||
return value
|
||||
.replace(/[^0-9.]/g, '') // Only Numbers
|
||||
.replace(/^(?:0+(?=[1-9])|0+(?=0$))/gm, '') // No leading Zeros and only one Zero allowed
|
||||
.replace(/(\..*)\./g, '$1'); // No special characters
|
||||
}
|
||||
|
||||
function checkBoundaries(value: string, option: RangeFilterOption): string {
|
||||
if (Number(value) <= Number(option.maxValue) && Number(value) >= Number(option.minValue)) {
|
||||
return value;
|
||||
} else {
|
||||
return Number(value) > Number(option.maxValue) ? option.maxValue : Number(value) < Number(option.minValue) ? option.minValue : '';
|
||||
}
|
||||
}
|
||||
|
||||
function compareWithStartValue(value: string, control: AbstractControl): { error: boolean } {
|
||||
const result = { error: false };
|
||||
const startCtrl = control?.parent?.get('start');
|
||||
if (Number(startCtrl.value) > Number(value) && startCtrl.value.length > 0 && value !== '') {
|
||||
result.error = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function compareWithStopValue(value: string, control: AbstractControl): { error: boolean; value: string } {
|
||||
const result = { error: false, value };
|
||||
const stopCtrl = control?.parent?.get('stop');
|
||||
if (Number(value) > Number(stopCtrl.value) && stopCtrl.value.length > 0) {
|
||||
result.value = stopCtrl.value;
|
||||
result.error = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { EventEmitter } from '@angular/core';
|
||||
import { Filter, FilterOption } from '../models';
|
||||
import { Filter, FilterOption, RangeFilter, RangeFilterOption, SelectFilter, SelectFilterOption } from '../models';
|
||||
import { isRangeFilterOption, isSelectFilterOption } from '../type-guards';
|
||||
|
||||
export abstract class FilterGroup {
|
||||
@@ -25,21 +25,20 @@ export abstract class FilterGroup {
|
||||
this.updateView.emit();
|
||||
}
|
||||
|
||||
toggleOption(filter: Filter, option: FilterOption) {
|
||||
toggleOption(filter: SelectFilter, option: SelectFilterOption) {
|
||||
const optionRef = this.getOptionRef(filter, option);
|
||||
if (isSelectFilterOption(optionRef)) {
|
||||
optionRef.selected = !optionRef.selected;
|
||||
this.valueChange.emit(this.value);
|
||||
this.updateView.emit();
|
||||
}
|
||||
}
|
||||
|
||||
setRangeOption(filter: RangeFilter, option: RangeFilterOption) {
|
||||
const optionRef = this.getOptionRef(filter, option);
|
||||
if (isRangeFilterOption(optionRef)) {
|
||||
console.log('BEFORE: ', optionRef, option);
|
||||
optionRef.selected = option.selected;
|
||||
if (isRangeFilterOption(option)) {
|
||||
optionRef.value = option.value;
|
||||
}
|
||||
console.log(optionRef, option);
|
||||
optionRef.value = option.value;
|
||||
this.valueChange.emit(this.value);
|
||||
this.updateView.emit();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Component, ChangeDetectionStrategy, Input, EventEmitter, Output, ChangeDetectorRef } from '@angular/core';
|
||||
import { Filter, FilterOption } from '../../models';
|
||||
import { isSelectFilter } from '../../type-guards';
|
||||
import { Filter, FilterOption, RangeFilterOption, SelectFilterOption } from '../../models';
|
||||
import { isRangeFilter, isRangeFilterOption, isSelectFilter } from '../../type-guards';
|
||||
import { isSelectFilterOption } from '../../type-guards/select-filter-option.type-guard';
|
||||
import { cloneFilter } from '../../utils';
|
||||
|
||||
@@ -25,6 +25,10 @@ export class UiSelectedFilterOptionsComponent {
|
||||
const selected = filter.options.filter((f) => f.selected);
|
||||
return [...aggr, ...selected];
|
||||
}
|
||||
if (isRangeFilter(filter)) {
|
||||
const range = filter.options.filter((f) => f.selected);
|
||||
return [...aggr, ...range];
|
||||
}
|
||||
|
||||
return [...aggr];
|
||||
}, []);
|
||||
@@ -64,6 +68,14 @@ export class UiSelectedFilterOptionsComponent {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (isRangeFilter(filter)) {
|
||||
if (isRangeFilter(val)) {
|
||||
val.options.forEach((option) => {
|
||||
result = result || filter.options.find((o) => o.id === option.id).selected !== option.selected;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
@@ -80,6 +92,12 @@ export class UiSelectedFilterOptionsComponent {
|
||||
unselectOptions(o.options);
|
||||
}
|
||||
}
|
||||
|
||||
if (isRangeFilterOption(o)) {
|
||||
if (o.id === option.id) {
|
||||
o.selected = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user