From 6f03b8ae2f424745aad53d553f3208ca199d7eba Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 14 Jan 2026 14:04:05 +0200 Subject: [PATCH] UI: Fixed country autocomplete after review --- ui-ngx/src/app/core/utils.ts | 6 +-- .../country-autocomplete.component.html | 4 +- .../country-autocomplete.component.scss | 10 ++-- .../country-autocomplete.component.ts | 49 +++++++++++++------ .../assets/locale/locale.constant-en_US.json | 2 +- 5 files changed, 46 insertions(+), 25 deletions(-) diff --git a/ui-ngx/src/app/core/utils.ts b/ui-ngx/src/app/core/utils.ts index e0665d4eb1..4c7a241931 100644 --- a/ui-ngx/src/app/core/utils.ts +++ b/ui-ngx/src/app/core/utils.ts @@ -999,11 +999,11 @@ export const validateEmail = (control: AbstractControl): ValidationErrors | null return emailRegex.test(control.value) ? null : {email: true}; }; -export const requireMatch = (): ValidatorFn => { +export const objectRequired = (): ValidatorFn => { return (control: AbstractControl): ValidationErrors | null => { const value = control.value; - if (value && typeof value === 'string') { - return { requireMatch: { value: value } }; + if (value && !isObject(value)) { + return { objectRequired: true }; } return null; }; diff --git a/ui-ngx/src/app/shared/components/country-autocomplete.component.html b/ui-ngx/src/app/shared/components/country-autocomplete.component.html index 61a874431a..16018c7e75 100644 --- a/ui-ngx/src/app/shared/components/country-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/country-autocomplete.component.html @@ -61,7 +61,7 @@ {{ requiredText }} - - {{ requiredMatchText }} + + {{ objectRequiredText }} diff --git a/ui-ngx/src/app/shared/components/country-autocomplete.component.scss b/ui-ngx/src/app/shared/components/country-autocomplete.component.scss index d1034b57f8..72de6174ba 100644 --- a/ui-ngx/src/app/shared/components/country-autocomplete.component.scss +++ b/ui-ngx/src/app/shared/components/country-autocomplete.component.scss @@ -17,11 +17,13 @@ .mat-form-field-appearance-fill { .mat-mdc-form-field-icon-prefix { align-self: baseline; + } + } - & > * { - color: initial; - padding-left: 8px; - } + .mat-mdc-form-field-icon-prefix { + & > * { + color: initial; + padding-left: 8px; } } } diff --git a/ui-ngx/src/app/shared/components/country-autocomplete.component.ts b/ui-ngx/src/app/shared/components/country-autocomplete.component.ts index 540a0f08cd..4bc49bbbb0 100644 --- a/ui-ngx/src/app/shared/components/country-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/country-autocomplete.component.ts @@ -14,7 +14,18 @@ /// limitations under the License. /// -import { Component, ElementRef, EventEmitter, forwardRef, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { + Component, + ElementRef, + EventEmitter, + forwardRef, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges, + ViewChild +} from '@angular/core'; import { Country, CountryData } from '@shared/models/country.models'; import { ControlValueAccessor, @@ -26,7 +37,7 @@ import { Validator, Validators } from '@angular/forms'; -import { isNotEmptyStr, requireMatch } from '@core/utils'; +import { isNotEmptyStr, objectRequired } from '@core/utils'; import { Observable, of } from 'rxjs'; import { debounceTime, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators'; import { MatFormFieldAppearance, SubscriptSizing } from '@angular/material/form-field'; @@ -56,7 +67,7 @@ interface CountrySearchData extends Country { } ] }) -export class CountryAutocompleteComponent implements OnInit, ControlValueAccessor, Validator { +export class CountryAutocompleteComponent implements OnInit, OnChanges, ControlValueAccessor, Validator { @Input() labelText = this.translate.instant('contact.country'); @@ -65,7 +76,7 @@ export class CountryAutocompleteComponent implements OnInit, ControlValueAccesso requiredText = this.translate.instant('contact.country-required'); @Input() - requiredMatchText = this.translate.instant('contact.country-required-match'); + objectRequiredText = this.translate.instant('contact.country-object-required'); @Input() autocompleteHint: string; @@ -111,15 +122,25 @@ export class CountryAutocompleteComponent implements OnInit, ControlValueAccesso private countryData: CountryData, private translate: TranslateService) { this.countryFormGroup = this.fb.group({ - country: ['', requireMatch()] + country: ['', objectRequired()] }); } - ngOnInit(): void { - if (this.required) { - this.countryFormGroup.get('country').addValidators(Validators.required); - this.countryFormGroup.get('country').updateValueAndValidity(); + ngOnChanges(changes: SimpleChanges) { + if (changes.required) { + const requiredChanges = changes.required; + if (requiredChanges.currentValue !== requiredChanges.previousValue) { + if (requiredChanges.currentValue) { + this.countryFormGroup.get('country').addValidators(Validators.required); + } else { + this.countryFormGroup.get('country').removeValidators(Validators.required); + } + this.countryFormGroup.get('country').updateValueAndValidity(); + } } + } + + ngOnInit(): void { this.filteredCountries = this.countryFormGroup.get('country').valueChanges.pipe( debounceTime(150), tap(value => { @@ -190,12 +211,10 @@ export class CountryAutocompleteComponent implements OnInit, ControlValueAccesso const value = control.value; if (value && typeof value === 'string') { - const filterValue = value.trim().toLowerCase(); - const foundCountry = this.allCountries.find(c => c.name.toLowerCase() === filterValue); - - if (foundCountry) { - control.setValue(foundCountry); - this.autocompleteTrigger.closePanel(); + const foundCountry = this.fetchCountries(value); + if (foundCountry.length === 1) { + control.setValue(foundCountry[0]); + this.autocompleteTrigger?.closePanel(); } } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 80395efea2..6b70ac45d6 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1194,7 +1194,7 @@ "contact": { "country": "Country", "country-required": "Country is required.", - "country-required-match": "Please select a valid country from the list.", + "country-object-required": "Please select a valid country from the list.", "city": "City", "state": "State / Province", "postal-code": "Zip / Postal Code",