我创建了这个名为country-flag-dropdown.ts和html的组件 成分:
import {Component, OnInit, Input, Output, EventEmitter} from "@angular/core";
import {FormGroup, FormControl} from "@angular/forms";
import {CountryDataService} from "projects/pitxpress-admin-app/src/app/pitxpress/api-services/country/country-data.service";
import {ICountry} from "projects/pitxpress-admin-app/src/app/pitxpress/api-services/country/models/country.interface";
import {PhoneNumberUtil, PhoneNumberFormat} from "google-libphonenumber";
/**
* Country flag dropdown component.
*/
@Component({
selector: "app-country-flag-dropdown",
templateUrl: "./country-flag-dropdown.component.html",
styleUrls: ["./country-flag-dropdown.component.scss"],
})
export class CountryFlagDropdownComponent implements OnInit {
/**
* Form group for the component.
*/
@Input() public form!: FormGroup;
/**
* Control name for the phone number input.
*/
@Input() public controlName!: string;
/**
* Event emitter for phone number changes.
*/
@Output() public phoneNumberChange = new EventEmitter<string>();
/**
* List of countries.
*/
public countries: ICountry[] = [];
/**
* Selected dial code.
*/
public selectedDialCode: string = "";
/**
* Selected country.
*/
public selectedCountry: ICountry | undefined;
/**
* Country control form control.
*/
public countryControl = new FormControl();
/**
* Phone number utility instance.
*/
private phoneNumberUtil = PhoneNumberUtil.getInstance();
/**
* Form group for country control.
*/
public countryForm = new FormGroup({
countryControl: new FormControl(),
});
/**
* Constructor.
* @param countryDataService Country data service instance.
*/
constructor(private countryDataService: CountryDataService) {}
/**
* Initialize component.
*/
public ngOnInit(): void {
// Initialize countries data and set initial country to United States if it exists
this.countryDataService.getCountries().subscribe((countries) => {
this.countries = countries;
this.initInitialCountry();
this.checkExistingPhoneNumber();
});
// Subscribe to country control value changes
this.countryControl.valueChanges.subscribe((value) => {
this.onCountryChange(value);
});
}
/**
* Initialize initial country to United States if it exists.
*/
private initInitialCountry(): void {
const usa = this.countries.find((country) => country.isoCode2 === "US");
if (usa) {
this.selectedCountry = usa;
this.selectedDialCode = usa.dialCodes[0];
this.countryControl.setValue(this.selectedDialCode, {emitEvent: false});
this.form.get(this.controlName)?.setValue(this.selectedDialCode);
}
}
/**
* Check if there's an existing phone number.
*/
private checkExistingPhoneNumber(): void {
const phoneNumber = this.form.get(this.controlName)?.value;
if (phoneNumber) {
this.selectedDialCode = this.extractDialCode(phoneNumber);
this.form.get(this.controlName)?.setValue(phoneNumber);
const iso2Code = this.getIso2CodeFromPhoneNumber(phoneNumber);
if (iso2Code) {
this.updateCountrySelectionByIsoCode(iso2Code);
}
}
}
/**
* Handle country change event.
* @param dialCode Selected dial code.
*/
public onCountryChange(dialCode: string): void {
const selectedCountry = this.countries.find((country) => country.dialCodes.includes(dialCode));
if (selectedCountry) {
this.selectedDialCode = dialCode;
this.selectedCountry = selectedCountry;
const inputValue = this.form.get(this.controlName)?.value.replace(this.selectedDialCode, "");
this.form.get(this.controlName)?.setValue(this.selectedDialCode + inputValue);
this.phoneNumberChange.emit(this.selectedDialCode + inputValue);
} else {
// If the country is selected from the dropdown, update the selectedCountry and selectedDialCode
const selectedCountry = this.countries.find((country) => country.dialCodes[0] === dialCode);
if (selectedCountry) {
this.selectedCountry = selectedCountry;
this.selectedDialCode = dialCode;
}
}
}
/**
* Handle phone number input event.
* @param event Input event.
*/
public onPhoneNumberInput(event: any): void {
const inputElement = event.target as HTMLInputElement;
const inputValue = inputElement.value.trim();
this.formatPhoneNumber(inputValue);
const countryCode = this.getCountryCodeFromPhoneNumber(inputValue);
if (countryCode) {
const isoCode = this.phoneNumberUtil.getRegionCodeForCountryCode(parseInt(countryCode));
if (isoCode) {
this.updateCountrySelectionByIsoCode(isoCode);
}
}
// Update the phone number value in the form
this.form.get(this.controlName)?.setValue(inputValue);
// Emit the phone number change event
this.phoneNumberChange.emit(inputValue);
}
/**
* Extract dial code from phone number.
* @param phoneNumber Phone number.
* @returns Dial code.
*/
private extractDialCode(phoneNumber: string): string {
for (const country of this.countries) {
if (Array.isArray(country.dialCodes)) {
for (const dialCode of country.dialCodes) {
if (phoneNumber.startsWith(dialCode)) {
return dialCode;
}
}
}
}
return "";
}
/**
* Update country selection by ISO code.
* @param isoCode ISO code.
*/
private updateCountrySelectionByIsoCode(isoCode: string): void {
const selectedCountry = this.countries.find((country) => country.slug === isoCode);
if (selectedCountry) {
console.log("Updating country selection by ISO code:", selectedCountry);
this.selectedCountry = selectedCountry;
this.selectedDialCode = selectedCountry.dialCodes[0];
this.countryControl.setValue(this.selectedDialCode, {emitEvent: false});
}
}
/**
* Get ISO 2 code from phone number.
* @param phoneNumber Phone number.
* @returns ISO 2 code.
*/
private getIso2CodeFromPhoneNumber(phoneNumber: string): string {
try {
const number = this.phoneNumberUtil.parse(phoneNumber, ""); // Use the default region for parsing
return this.phoneNumberUtil.getRegionCodeForNumber(number) || "";
} catch (error) {
console.error("Error parsing phone number:", error);
return "";
}
}
/**
* Get country code from phone number.
* @param phoneNumber Phone number.
* @returns Country code.
*/
private getCountryCodeFromPhoneNumber(phoneNumber: string): string {
try {
const number = this.phoneNumberUtil.parse(phoneNumber, "");
return number?.getCountryCode()?.toString() || "";
} catch (error) {
console.error("Error parsing phone number:", error);
return "";
}
}
/**
* Format phone number.
* @param phoneNumber Phone number.
* @returns Formatted phone number.
*/
public formatPhoneNumber(phoneNumber: string): string {
try {
const number = this.phoneNumberUtil.parse(phoneNumber, this.selectedCountry?.isoCode2);
return this.phoneNumberUtil.format(number, PhoneNumberFormat.INTERNATIONAL);
} catch (error) {
console.error("Error formatting phone number:", error);
return phoneNumber;
}
}
}
HTML:
<div class="input-group country-dropdown-group" [formGroup]="form">
<form [formGroup]="countryForm">
<p-dropdown
[options]="countries"
optionLabel="name"
optionValue="dialCodes[0]"
appendTo="body"
[filter]="true"
filterBy="name"
formControlName="countryControl"
class="p-inputgroup-addon country-flag-selector">
<ng-template let-country pTemplate="selectedItem">
<div class="country-selector-item">
<img [src]="'assets/flags/' + selectedCountry?.slug + '.svg'" class="country-flag" />
<span>{{ selectedCountry?.slug }}</span>
</div>
</ng-template>
<ng-template let-country pTemplate="item">
<div class="country-selector-item">
<img [src]="'assets/flags/' + country.slug + '.svg'" class="country-flag" />
<span>{{ country.name }}</span>
</div>
</ng-template>
</p-dropdown>
</form>
<input
type="text"
pInputText
[formControlName]="controlName"
maxlength="15"
placeholder="Phone Number"
class="form-control"
(input)="onPhoneNumberInput($event)"
[value]="formatPhoneNumber(form.get(controlName)?.value)"/>
</div>
我的目标是创建一个国家/地区国旗下拉列表,用户可以在其中选择国旗或输入电话号码,然后就会显示国旗。但使用当前代码,我无法从下拉列表中选择标志,并且它不会反映在用户界面中。
我想我对它的问题有一个大概的了解。我有一个 @Input 表单,但我也有一个 CountyForm。这两种形式似乎都是在不同的地方访问的,这有点令人困惑。 @Input 表单的想法是尝试添加到父组件上的现有表单。在这一行中
<img [src]="'assets/flags/' + selectedCountry?.slug + '.svg'" class="country-flag" />
如果我将 selectedCountry?.slug 更改为国家/地区,我可以从下拉列表中选择标志,它将反映在 UI 上,但当我输入时我无法检测到标志一个数字,因此当我需要两种功能时,它会剥夺一种功能。我只是好奇我怎样才能做到这一点?
您可以尝试在您的 CountryFlagDropdownComponent OnInit 中添加此订阅:
this.form.get(this.controlName)?.valueChanges.subscribe((value) => {
this.onPhoneNumberInput(value);
});
onPhoneNumberInput 方法将电话号码作为输入并更新选定的国家/地区,onCountryChange 方法根据下拉列表中选定的国家/地区更新电话号码。
public onPhoneNumberInput(phoneNumber: string): void {
this.formatPhoneNumber(phoneNumber);
const countryCode = this.getCountryCodeFromPhoneNumber(phoneNumber);
if (countryCode) {
const isoCode = this.phoneNumberUtil.getRegionCodeForCountryCode(parseInt(countryCode));
if (isoCode) {
this.updateCountrySelectionByIsoCode(isoCode);
}
}
this.form.get(this.controlName)?.setValue(phoneNumber);
this.phoneNumberChange.emit(phoneNumber);
}
public onCountryChange(dialCode: string): void {
const selectedCountry = this.countries.find((country) => country.dialCodes.includes(dialCode));
if (selectedCountry) {
this.selectedDialCode = dialCode;
this.selectedCountry = selectedCountry;
const inputValue = this.form.get(this.controlName)?.value.replace(this.selectedDialCode, "");
this.form.get(this.controlName)?.setValue(this.selectedDialCode + inputValue);
this.phoneNumberChange.emit(this.selectedDialCode + inputValue);
}
}
最后你应该用
(input)="onPhoneNumberInput($event.target.value)"
更新 html