diff --git a/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts index c6c8a5ed51..d5299a52ea 100644 --- a/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/boolean-filter-predicate.component.ts @@ -15,11 +15,21 @@ /// import { Component, forwardRef, Input, OnInit } from '@angular/core'; -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { + ControlValueAccessor, + FormBuilder, + FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + ValidationErrors, + Validator, + Validators +} from '@angular/forms'; import { BooleanFilterPredicate, BooleanOperation, - booleanOperationTranslationMap, EntityKeyValueType, + booleanOperationTranslationMap, + EntityKeyValueType, FilterPredicateType } from '@shared/models/query/query.models'; @@ -32,10 +42,15 @@ import { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => BooleanFilterPredicateComponent), multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => BooleanFilterPredicateComponent), + multi: true } ] }) -export class BooleanFilterPredicateComponent implements ControlValueAccessor, OnInit { +export class BooleanFilterPredicateComponent implements ControlValueAccessor, Validator, OnInit { @Input() disabled: boolean; @@ -73,7 +88,7 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On registerOnTouched(fn: any): void { } - setDisabledState?(isDisabled: boolean): void { + setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (this.disabled) { this.booleanFilterPredicateFormGroup.disable({emitEvent: false}); @@ -82,17 +97,20 @@ export class BooleanFilterPredicateComponent implements ControlValueAccessor, On } } + validate(): ValidationErrors | null { + return this.booleanFilterPredicateFormGroup ? null : { + booleanFilterPredicate: {valid: false} + }; + } + writeValue(predicate: BooleanFilterPredicate): void { this.booleanFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); this.booleanFilterPredicateFormGroup.get('value').patchValue(predicate.value, {emitEvent: false}); } private updateModel() { - let predicate: BooleanFilterPredicate = null; - if (this.booleanFilterPredicateFormGroup.valid) { - predicate = this.booleanFilterPredicateFormGroup.getRawValue(); - predicate.type = FilterPredicateType.BOOLEAN; - } + const predicate: BooleanFilterPredicate = this.booleanFilterPredicateFormGroup.getRawValue(); + predicate.type = FilterPredicateType.BOOLEAN; this.propagateChange(predicate); } diff --git a/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts index 9f4acfc3c6..b177f118c0 100644 --- a/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/complex-filter-predicate.component.ts @@ -16,11 +16,7 @@ import { Component, forwardRef, Input, OnInit } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; -import { - ComplexFilterPredicate, - ComplexFilterPredicateInfo, - EntityKeyValueType -} from '@shared/models/query/query.models'; +import { ComplexFilterPredicateInfo, EntityKeyValueType } from '@shared/models/query/query.models'; import { MatDialog } from '@angular/material/dialog'; import { ComplexFilterPredicateDialogComponent, @@ -71,7 +67,7 @@ export class ComplexFilterPredicateComponent implements ControlValueAccessor, On registerOnTouched(fn: any): void { } - setDisabledState?(isDisabled: boolean): void { + setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; } diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts index 3c16b01319..75c9bd3ce8 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-list.component.ts @@ -21,7 +21,10 @@ import { FormArray, FormBuilder, FormGroup, + NG_VALIDATORS, NG_VALUE_ACCESSOR, + ValidationErrors, + Validator, Validators } from '@angular/forms'; import { Observable, of, Subscription } from 'rxjs'; @@ -49,10 +52,15 @@ import { map } from 'rxjs/operators'; provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => FilterPredicateListComponent), multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => FilterPredicateListComponent), + multi: true } ] }) -export class FilterPredicateListComponent implements ControlValueAccessor, OnInit { +export class FilterPredicateListComponent implements ControlValueAccessor, Validator, OnInit { @Input() disabled: boolean; @@ -108,6 +116,12 @@ export class FilterPredicateListComponent implements ControlValueAccessor, OnIni } } + validate(control: AbstractControl): ValidationErrors | null { + return this.filterListFormGroup.valid ? null : { + filterList: {valid: false} + }; + } + writeValue(predicates: Array): void { if (this.valueChangeSubscription) { this.valueChangeSubscription.unsubscribe(); @@ -178,7 +192,7 @@ export class FilterPredicateListComponent implements ControlValueAccessor, OnIni private updateModel() { const predicates: Array = this.filterListFormGroup.getRawValue().predicates; - if (this.filterListFormGroup.valid && predicates.length) { + if (predicates.length) { this.propagateChange(predicates); } else { this.propagateChange(null); diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.ts b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.ts index 7417317dae..934a4774fb 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filter-predicate-value.component.ts @@ -19,7 +19,10 @@ import { ControlValueAccessor, FormBuilder, FormGroup, + NG_VALIDATORS, NG_VALUE_ACCESSOR, + ValidationErrors, + Validator, ValidatorFn, Validators } from '@angular/forms'; @@ -39,10 +42,15 @@ import { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => FilterPredicateValueComponent), multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => FilterPredicateValueComponent), + multi: true } ] }) -export class FilterPredicateValueComponent implements ControlValueAccessor, OnInit { +export class FilterPredicateValueComponent implements ControlValueAccessor, Validator, OnInit { private readonly inheritModeForSources: DynamicValueSourceType[] = [ DynamicValueSourceType.CURRENT_CUSTOMER, @@ -62,7 +70,22 @@ export class FilterPredicateValueComponent implements ControlValueAccessor, OnIn } } - @Input() onlyUserDynamicSource = false; + private onlyUserDynamicSourceValue = false; + + @Input() + set onlyUserDynamicSource(dynamicMode: boolean) { + this.onlyUserDynamicSourceValue = dynamicMode; + if (this.filterPredicateValueFormGroup) { + this.updateValidationDynamicMode(); + setTimeout(() => { + this.updateModel(); + }, 0); + } + } + + get onlyUserDynamicSource(): boolean { + return this.onlyUserDynamicSourceValue; + } @Input() valueType: EntityKeyValueType; @@ -83,6 +106,7 @@ export class FilterPredicateValueComponent implements ControlValueAccessor, OnIn allow = true; private propagateChange = null; + private propagateChangePending = false; constructor(private fb: FormBuilder) { } @@ -126,6 +150,7 @@ export class FilterPredicateValueComponent implements ControlValueAccessor, OnIn this.updateShowInheritMode(sourceType); } ); + this.updateValidationDynamicMode(); this.filterPredicateValueFormGroup.valueChanges.subscribe(() => { this.updateModel(); }); @@ -133,12 +158,18 @@ export class FilterPredicateValueComponent implements ControlValueAccessor, OnIn registerOnChange(fn: any): void { this.propagateChange = fn; + if (this.propagateChangePending) { + this.propagateChangePending = false; + setTimeout(() => { + this.updateModel(); + }, 0); + } } registerOnTouched(fn: any): void { } - setDisabledState?(isDisabled: boolean): void { + setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (this.disabled) { this.filterPredicateValueFormGroup.disable({emitEvent: false}); @@ -147,28 +178,35 @@ export class FilterPredicateValueComponent implements ControlValueAccessor, OnIn } } + validate(): ValidationErrors | null { + return this.filterPredicateValueFormGroup.valid ? null : { + filterPredicateValue: {valid: false} + }; + } + writeValue(predicateValue: FilterPredicateValue): void { + this.propagateChangePending = false; this.filterPredicateValueFormGroup.get('defaultValue').patchValue(predicateValue.defaultValue, {emitEvent: false}); - this.filterPredicateValueFormGroup.get('dynamicValue.sourceType').patchValue(predicateValue.dynamicValue ? - predicateValue.dynamicValue.sourceType : null, {emitEvent: false}); - this.filterPredicateValueFormGroup.get('dynamicValue.sourceAttribute').patchValue(predicateValue.dynamicValue ? - predicateValue.dynamicValue.sourceAttribute : null, {emitEvent: false}); - this.filterPredicateValueFormGroup.get('dynamicValue.inherit').patchValue(predicateValue.dynamicValue ? - predicateValue.dynamicValue.inherit : false, {emitEvent: false}); + this.filterPredicateValueFormGroup.get('dynamicValue').patchValue({ + sourceType: predicateValue.dynamicValue ? predicateValue.dynamicValue.sourceType : null, + sourceAttribute: predicateValue.dynamicValue ? predicateValue.dynamicValue.sourceAttribute : null, + inherit: predicateValue.dynamicValue ? predicateValue.dynamicValue.inherit : false + }, {emitEvent: this.onlyUserDynamicSource}); this.updateShowInheritMode(predicateValue?.dynamicValue?.sourceType); } private updateModel() { - let predicateValue: FilterPredicateValue = null; - if (this.filterPredicateValueFormGroup.valid) { - predicateValue = this.filterPredicateValueFormGroup.getRawValue(); - if (predicateValue.dynamicValue) { - if (!predicateValue.dynamicValue.sourceType || !predicateValue.dynamicValue.sourceAttribute) { - predicateValue.dynamicValue = null; - } + const predicateValue: FilterPredicateValue = this.filterPredicateValueFormGroup.getRawValue(); + if (predicateValue.dynamicValue) { + if (!predicateValue.dynamicValue.sourceType || !predicateValue.dynamicValue.sourceAttribute) { + predicateValue.dynamicValue = null; } } - this.propagateChange(predicateValue); + if (this.propagateChange) { + this.propagateChange(predicateValue); + } else { + this.propagateChangePending = true; + } } private updateShowInheritMode(sourceType: DynamicValueSourceType) { @@ -179,4 +217,16 @@ export class FilterPredicateValueComponent implements ControlValueAccessor, OnIn this.inheritMode = false; } } + + private updateValidationDynamicMode() { + if (this.onlyUserDynamicSource) { + this.filterPredicateValueFormGroup.get('dynamicValue.sourceType').setValidators(Validators.required); + this.filterPredicateValueFormGroup.get('dynamicValue.sourceAttribute').setValidators(Validators.required); + } else { + this.filterPredicateValueFormGroup.get('dynamicValue.sourceType').clearValidators(); + this.filterPredicateValueFormGroup.get('dynamicValue.sourceAttribute').clearValidators(); + } + this.filterPredicateValueFormGroup.get('dynamicValue.sourceType').updateValueAndValidity({emitEvent: false}); + this.filterPredicateValueFormGroup.get('dynamicValue.sourceAttribute').updateValueAndValidity({emitEvent: false}); + } } diff --git a/ui-ngx/src/app/modules/home/components/filter/filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/filter-predicate.component.ts index 69972b6a90..17361f55bd 100644 --- a/ui-ngx/src/app/modules/home/components/filter/filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/filter-predicate.component.ts @@ -15,11 +15,17 @@ /// import { Component, forwardRef, Input, OnInit } from '@angular/core'; -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; import { - EntityKeyValueType, - FilterPredicateType, KeyFilterPredicate, KeyFilterPredicateInfo -} from '@shared/models/query/query.models'; + ControlValueAccessor, + FormBuilder, + FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + ValidationErrors, + Validator, + Validators +} from '@angular/forms'; +import { EntityKeyValueType, FilterPredicateType, KeyFilterPredicateInfo } from '@shared/models/query/query.models'; @Component({ selector: 'tb-filter-predicate', @@ -30,10 +36,15 @@ import { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => FilterPredicateComponent), multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => FilterPredicateComponent), + multi: true } ] }) -export class FilterPredicateComponent implements ControlValueAccessor, OnInit { +export class FilterPredicateComponent implements ControlValueAccessor, Validator, OnInit { @Input() disabled: boolean; @@ -75,7 +86,7 @@ export class FilterPredicateComponent implements ControlValueAccessor, OnInit { registerOnTouched(fn: any): void { } - setDisabledState?(isDisabled: boolean): void { + setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (this.disabled) { this.filterPredicateFormGroup.disable({emitEvent: false}); @@ -84,6 +95,12 @@ export class FilterPredicateComponent implements ControlValueAccessor, OnInit { } } + validate(): ValidationErrors | null { + return this.filterPredicateFormGroup.valid ? null : { + filterPredicate: {valid: false} + }; + } + writeValue(predicate: KeyFilterPredicateInfo): void { this.type = predicate.keyFilterPredicate.type; this.filterPredicateFormGroup.get('predicate').patchValue(predicate.keyFilterPredicate, {emitEvent: false}); diff --git a/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.ts b/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.ts index 1229f18ec2..c1d1a1db82 100644 --- a/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/key-filter-list.component.ts @@ -22,7 +22,10 @@ import { FormBuilder, FormControl, FormGroup, + NG_VALIDATORS, NG_VALUE_ACCESSOR, + ValidationErrors, + Validator, Validators } from '@angular/forms'; import { Observable, Subscription } from 'rxjs'; @@ -46,10 +49,15 @@ import { EntityId } from '@shared/models/id/entity-id'; provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => KeyFilterListComponent), multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => KeyFilterListComponent), + multi: true } ] }) -export class KeyFilterListComponent implements ControlValueAccessor, OnInit { +export class KeyFilterListComponent implements ControlValueAccessor, Validator, OnInit { @Input() disabled: boolean; @@ -104,6 +112,12 @@ export class KeyFilterListComponent implements ControlValueAccessor, OnInit { } } + validate(): ValidationErrors | null { + return this.keyFilterListFormGroup.valid && this.keyFiltersControl.valid ? null : { + keyFilterList: {valid: false} + }; + } + writeValue(keyFilters: Array): void { if (this.valueChangeSubscription) { this.valueChangeSubscription.unsubscribe(); diff --git a/ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.ts index 434c90fa80..2b24a5a6b1 100644 --- a/ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/numeric-filter-predicate.component.ts @@ -15,7 +15,16 @@ /// import { Component, forwardRef, Input, OnInit } from '@angular/core'; -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { + ControlValueAccessor, + FormBuilder, + FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + ValidationErrors, + Validator, + Validators +} from '@angular/forms'; import { EntityKeyValueType, FilterPredicateType, @@ -33,10 +42,15 @@ import { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NumericFilterPredicateComponent), multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => NumericFilterPredicateComponent), + multi: true } ] }) -export class NumericFilterPredicateComponent implements ControlValueAccessor, OnInit { +export class NumericFilterPredicateComponent implements ControlValueAccessor, Validator, OnInit { @Input() disabled: boolean; @@ -76,7 +90,7 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, On registerOnTouched(fn: any): void { } - setDisabledState?(isDisabled: boolean): void { + setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; if (this.disabled) { this.numericFilterPredicateFormGroup.disable({emitEvent: false}); @@ -85,17 +99,20 @@ export class NumericFilterPredicateComponent implements ControlValueAccessor, On } } + validate(): ValidationErrors | null { + return this.numericFilterPredicateFormGroup.valid ? null : { + numericFilterPredicate: {valid: false} + }; + } + writeValue(predicate: NumericFilterPredicate): void { this.numericFilterPredicateFormGroup.get('operation').patchValue(predicate.operation, {emitEvent: false}); this.numericFilterPredicateFormGroup.get('value').patchValue(predicate.value, {emitEvent: false}); } private updateModel() { - let predicate: NumericFilterPredicate = null; - if (this.numericFilterPredicateFormGroup.valid) { - predicate = this.numericFilterPredicateFormGroup.getRawValue(); - predicate.type = FilterPredicateType.NUMERIC; - } + const predicate: NumericFilterPredicate = this.numericFilterPredicateFormGroup.getRawValue(); + predicate.type = FilterPredicateType.NUMERIC; this.propagateChange(predicate); } diff --git a/ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.ts index 11b4dad275..3caa282576 100644 --- a/ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/filter/string-filter-predicate.component.ts @@ -15,7 +15,16 @@ /// import { Component, forwardRef, Input, OnInit } from '@angular/core'; -import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; +import { + ControlValueAccessor, + FormBuilder, + FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + ValidationErrors, + Validator, + Validators +} from '@angular/forms'; import { EntityKeyValueType, FilterPredicateType, @@ -33,10 +42,15 @@ import { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => StringFilterPredicateComponent), multi: true + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => StringFilterPredicateComponent), + multi: true } ] }) -export class StringFilterPredicateComponent implements ControlValueAccessor, OnInit { +export class StringFilterPredicateComponent implements ControlValueAccessor, Validator, OnInit { @Input() disabled: boolean; @@ -90,12 +104,15 @@ export class StringFilterPredicateComponent implements ControlValueAccessor, OnI this.stringFilterPredicateFormGroup.get('ignoreCase').patchValue(predicate.ignoreCase, {emitEvent: false}); } + validate(c): ValidationErrors { + return this.stringFilterPredicateFormGroup.valid ? null : { + stringFilterPredicate: {valid: false} + }; + } + private updateModel() { - let predicate: StringFilterPredicate = null; - if (this.stringFilterPredicateFormGroup.valid) { - predicate = this.stringFilterPredicateFormGroup.getRawValue(); - predicate.type = FilterPredicateType.STRING; - } + const predicate: StringFilterPredicate = this.stringFilterPredicateFormGroup.getRawValue(); + predicate.type = FilterPredicateType.STRING; this.propagateChange(predicate); }