jackocnr/intl-tel-input

Bug: `nationalMode` and `showSelectedDialCode` together

alexisphilip opened this issue · 6 comments

Hello @jackocnr, I just discovered your library, and I really like it.

Use case

  • I'm using nationalMode because I find it great to improve the UX, since most users are used to their phone number without the international notation in front of it.
  • Most our users have phone numbers from France (FR, +33) and Réunion (EN, +262). Here lies the ambiguity: both countries have the same flag, since Réunion is a departement of France, but having its own country code.

Problem

Since they have the same flag, I need to use showSelectedDialCode to display the country code, to get rid of the ambiguity.

I found out in the docs that nationalMode actually disables showSelectedDialCode.

Question

Do you think it would be possible to let them behave together? I feel like each could be toggeled independantly, but not disable one another.

Thank you!

Hi there!

I found out in the docs that nationalMode actually disables showSelectedDialCode.

Can you point me to where in the readme it says this? (Are you using the latest version?)

As far as I'm aware, they can be used together. Are you having any problems using them together?

I read the docs again and realized I misread autoInsertDialCode to showSelectedDialCode ^^ nothing wrong with the docs!

Here is more about the issue.

Issue

I'm using v19.2.12.

Case 1️⃣ (✔️ pass)

When instanciating the utilsScript option: for any country, the phone formats as shown in the placeholder (since formatAsYouType defaults to true).

For France (FR, +33):

  • Placeholder: 01 02 03 04 05 (something like that, since nationalMode defaults to true)
  • Manual input: 0102030405
  • Formatted result: 01 02 03 04 05 (✔️ perfect)

Case 2️⃣ (❌ fail)

When instanciating the utilsScript and showSelectedDialCode options: for any country, the phone does not formats as shown in the placeholder. It only formats if your remove the first 0 (zero) character (at least for France & Réunion, haven't checked other countries).

For France (FR, +33):

  • Placeholder: 01 02 03 04 05 (something like that)
  • Manual input: 0102030405
  • Formatted result: 0102030405 (❌ here, it should be formatted as 01 02 03 04 05)

But if you input manually:

  • Input: 102030405 (without the first zero at the start)
  • Formatted result: 1 02 03 04 05

File structure

All files under css, img and js are the ones downloaded from the latest version, 19.2.12.

image

Intialization file index.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <input type="text" id="phone">
    <script src="js/script.min.js"></script>
    <script>
        const input = document.querySelector("#phone");
        intlTelInput(input, {
            utilsScript: "https://cdn.jsdelivr.net/npm/intl-tel-input@19.2.14/build/js/utils.js",
            showSelectedDialCode: true,
        });
    </script>
</body>
</html>

Thanks for that really clear write up!

Yes, there is definitely an issue currently where the placeholder does not match the format as-you-type. There is a related issue here and maybe this one too.

The crux of the issue is: we pass the typed number to libphonenumber for formatting, and when we do, we have to decide if we should prefix the dial code or not. There are 2 scenarios: (1) If the users follows the placeholder example and types their number in national format, then the number is valid as it is, so we don't need to do anything. (2) If however, the user assumes the displayed dial code is part of the number, and types the rest of the number in international format, then on its own the typed number is invalid - we need to prefix the dial code when passing the number to libphonenumber else the formatting wont work. (By the way, if we do prefix the dial code when passing the number to libphonenumber, we then strip it off again before displaying the formatted result in the input)

The quick fix is: when nationalMode is enabled, then assume the user will follow the placeholder example and type their number in national format, and so don't prefix the dial code when passing to libphonenumber. The risk here is: if a user ignores the placeholder, or doesn't see it or whatever, and assumes the displayed dial code is part of the number and types the rest of their number in international format, then the formatting will stop working. But hopefully this will happen rarely, and the user probably wont even know that there would normally be auto formatting, and everything else (validation etc) should still work fine.

Let me know your thoughts.

I've played around with it and here is something that works well for countries with 0 prefix that is not significant

The idea is this: we check if we are using nationalMode or not.

When not using national mode, the placeholder doesn't has the "0" therefore, it's much more logical when the dial code is displayed and format as you type work as expected

When national mode is enabled, the user may still type the leading 0 because that's what people do most of the time.
Therefore, we check if there is a leading 0 and remove it from the full number including prefix and mark this as replaced

Then we format, and we add it back. Tested in my web component, this works rather nicely.

    var val = this._getFullNumber().trim();
    var showSelectedDialCode = this.options.showSelectedDialCode;
    var dialCode = this.selectedCountryData.dialCode;
    var inputVal = this.telInput.value;
    var zeroPrefix = false;
    if(inputVal.length > 1 && inputVal.charAt(0) === "0" && this.options.nationalMode && showSelectedDialCode) {
        val = val.replace(dialCode + '0', dialCode);
        zeroPrefix = true;
    }
    var result = window.intlTelInputUtils ? intlTelInputUtils.formatNumberAsYouType(val, this.selectedCountryData.iso2) : val;
    // if showSelectedDialCode and they haven't (re)typed the dial code in the input as well, then remove the dial code
    if (showSelectedDialCode && inputVal.charAt(0) !== "+") {
        var afterDialCode = result.split("+".concat(dialCode))[1] || "";
        afterDialCode = afterDialCode.trim();
        if(zeroPrefix) {
            afterDialCode = "0" + afterDialCode;
        }
        return afterDialCode;
    }
    return result;

@lekoala thanks for the input. Yes I also considered this kind of approach, but I thought it might get too complicated. For example, do we know: exactly which countries this would affect? Is it always 0 that is the national prefix, or do some countries use something else? Are there certain situations (e.g. certain types of numbers) that follow a different pattern?

What do you think about the idea in my previous comment? Basically, the current logic is: if (showSelectedDialCode) then prefix dial code, and we would change it to if (showSelectedDialCode && !nationalMode) then prefix dial code

I think this is what you were suggesting here, and I replied with a concern that if the user thinks the dial code is part of the number, and types the rest of their number in international format (no 0), then it would break the AYT formatter, but on reflection, to do this they would have to ignore the placeholder example, so I think this will be rare, and also it's really not the end of the world if the AYT formatter doesn't work in this case!

I've gone ahead and released this fix in v19.2.15. Give it a try and let me know what you think!