Skip to content

feat(phone-number-input): show national (trunk) prefix indicator#2242

Draft
spike-rabbit wants to merge 1 commit into
mainfrom
feat/phone-number-input-national-prefix
Draft

feat(phone-number-input): show national (trunk) prefix indicator#2242
spike-rabbit wants to merge 1 commit into
mainfrom
feat/phone-number-input-national-prefix

Conversation

@spike-rabbit

@spike-rabbit spike-rabbit commented Jun 28, 2026

Copy link
Copy Markdown
Member

Display a non-editable (0) indicator between the country code and the
phone number input for countries that use a droppable 0 trunk prefix
(e.g. Germany), producing numbers like +49 (0) 176 .... The prefix is
detected via libphonenumber's national direct dialing prefix and is
omitted for countries without a 0 trunk prefix (e.g. US, Italy).


Documentation.
Examples.
Dashboards Demo.
Playwright report.

Coverage Reports:

Code Coverage

Display a non-editable `(0)` indicator between the country code and the
phone number input for countries that use a droppable `0` trunk prefix
(e.g. Germany), producing numbers like `+49 (0) 176 ...`. The prefix is
detected via libphonenumber's national direct dialing prefix and is
omitted for countries without a `0` trunk prefix (e.g. US, Italy).

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a national (trunk) prefix indicator to the phone number input component, refactoring selectedCountry to use Angular signals and adding a computed nationalPrefix property. The review feedback highlights critical runtime safety issues, specifically potential TypeError crashes in writeCountry() when handling undefined countries and in the validation logic due to unsafe non-null assertions on selectedCountry(). Additionally, the feedback suggests optimizing signal reads and eliminating non-null assertions in both the TypeScript logic and the HTML template by utilizing local variable bindings.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +362 to 372
if (!country) {
const countryCode = this.phoneUtil.getCountryCodeForRegion(
currentCountry ?? this.defaultCountry() ?? 'XX'
);
if (countryCode) {
this.selectedCountry = {
country = {
isoCode: currentCountry,
countryCode,
name: this.getCountryName(currentCountry)
};
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

If this.country() is undefined but defaultCountry() is defined (e.g., 'US'), currentCountry will be undefined at runtime. In this case, getCountryCodeForRegion will resolve the fallback country code successfully, but then this.getCountryName(currentCountry) will be called with undefined, throwing a runtime TypeError when calling toUpperCase() on it.

We should use a resolved fallback country variable for isoCode and getCountryName to prevent this crash.

    if (!country) {
      const resolvedCountry = currentCountry ?? this.defaultCountry() ?? 'XX';
      const countryCode = this.phoneUtil.getCountryCodeForRegion(resolvedCountry);
      if (countryCode) {
        country = {
          isoCode: resolvedCountry,
          countryCode,
          name: this.getCountryName(resolvedCountry)
        };
      }
    }

}

if (!this.countryList().some(c => c.value.isoCode === this.selectedCountry!.isoCode)) {
if (!this.countryList().some(c => c.value.isoCode === this.selectedCountry()!.isoCode)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The non-null assertion this.selectedCountry()!.isoCode can cause a runtime TypeError if selectedCountry() is undefined (for example, when the country is unsupported or cannot be resolved). We should safely retrieve the signal value and check if it is defined before accessing its properties.

    const selectedCountry = this.selectedCountry();
    if (!selectedCountry || !this.countryList().some(c => c.value.isoCode === selectedCountry.isoCode)) {

Comment on lines +389 to +392
if (this.selectedCountry()) {
this.placeholder = this.phoneUtil
.format(
this.phoneUtil.getExampleNumber(this.selectedCountry.isoCode),
this.phoneUtil.getExampleNumber(this.selectedCountry()!.isoCode),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To avoid multiple signal reads and eliminate the non-null assertion operator (!), we can assign this.selectedCountry() to a local variable.

Suggested change
if (this.selectedCountry()) {
this.placeholder = this.phoneUtil
.format(
this.phoneUtil.getExampleNumber(this.selectedCountry.isoCode),
this.phoneUtil.getExampleNumber(this.selectedCountry()!.isoCode),
const selectedCountry = this.selectedCountry();
if (selectedCountry) {
this.placeholder = this.phoneUtil
.format(
this.phoneUtil.getExampleNumber(selectedCountry.isoCode),

Comment on lines +35 to 40
@if (selectedCountry()) {
<span class="si-body ms-4" [id]="id() + '-value'">
<span class="visually-hidden">{{ selectedCountry.name }}</span>
+{{ selectedCountry.countryCode }}
<span class="visually-hidden">{{ selectedCountry()!.name }}</span>
+{{ selectedCountry()!.countryCode }}
</span>
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using the local variable binding syntax in Angular's native @if control flow (@if (selectedCountry(); as selected)) allows us to avoid multiple signal reads and eliminates the need for non-null assertions (!) in the template.

Suggested change
@if (selectedCountry()) {
<span class="si-body ms-4" [id]="id() + '-value'">
<span class="visually-hidden">{{ selectedCountry.name }}</span>
+{{ selectedCountry.countryCode }}
<span class="visually-hidden">{{ selectedCountry()!.name }}</span>
+{{ selectedCountry()!.countryCode }}
</span>
}
@if (selectedCountry(); as selected) {
<span class="si-body ms-4" [id]="id() + '-value'">
<span class="visually-hidden">{{ selected.name }}</span>
+{{ selected.countryCode }}
</span>
}
References
  1. Use native control flow (@if, @for, @switch) instead of *ngIf, *ngFor, *ngSwitch (link)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant