Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable and remove autoFormat feature #346

Closed
jackocnr opened this issue Jan 18, 2016 · 39 comments
Closed

Disable and remove autoFormat feature #346

jackocnr opened this issue Jan 18, 2016 · 39 comments

Comments

@jackocnr
Copy link
Owner

jackocnr commented Jan 18, 2016

I have been back and forth about this a lot - I spent a lot of time implementing the autoFormat feature and fixing bugs, and I think it's a super cool feature, BUT I think it's time to disable and remove it for the following reasons:

  • First and foremost, we are hacking libphonenumber to get this to work, which is dangerous. It was not made for this purpose, they do not support our use case, and they have explicitly advised us against using it this way.
  • When the user types we have to call preventDefault so we can control what happens, but this means we lose a bunch of useful native events like change and input, which other devs may depend on.
  • Last time I checked, autoFormat didn't work in Android Cordova apps, or in IE Mobile (see Browser Compatibility section of readme). Who knows what other browsers/versions/platforms make it not work properly.
  • There is no way around this incredibly counter-intuitive UX issue: Format assumes local number before national number #322 where you cannot type the first character from the placeholder. This affects 49 countries including the USA - see Disable and remove autoFormat feature #346 (comment).
  • Another minor issue: even if we find a fix for the above issue, it will lead to a new one: when a country placeholder starts with a formatting char (e.g. US starts with an open bracket), if you press that char to try and start the number, you will get a red flash as that is not an accepted key, but then it will still add the char because autoFormat does a lookahead and adds any upcoming formatting chars on each keypress, which leads to a confusing experience.
  • Then there's all the issues we have already come across, which suggests to me that there are so many more we don't yet know about. We get bug reports for the popular countries, but much less for the unpopular ones, which means most likely they are buggy and we just don't know about it.
  • Finally, restricting what the user can do in a regular <input> is considered bad practice by a lot of people (I have yet to find an example of Google or Facebook doing anything like this). As we have seen, this approach is very prone to bugs, and when there are bugs it can completely ruin the UX, or even render the whole input useless. It's a very dangerous approach.

Notes

I'm open to discussion, but at this point I'm pretty convinced, and would welcome a pull request that implemented this change.

@nlwillia
Copy link

I should preface this by acknowledging that I am not a domain expert on international phone numbers. I had not been exposed to E.164 before encountering this library. So what I assume to be sensible about how to deal with input issues comes from an engineering perspective, feedback from my own users and what experience I have with numbers in my own nationality.

I'm disappointed with the feedback we've gotten from libphonenumber about the problem of local formats. While I greatly respect their commitment to comprehensive and accurate metadata, I think they're limiting the practical applicability of their AsYouType formatter by only shipping it in a configuration that supports every configured format. There may be real world use cases internal to Google and elsewhere that benefit from that broader behavior, but if your goal is a full, standardized, unambiguous number then being able to choose to exclude local formats is a useful option to have when soliciting user input. My impression is not that they have rejected this line of reasoning so much as that they are satisfied with what they have and not interested in changing it. It would certainly take some work on their part to do so, and there may be more nuanced reasons from their experience why an E.164 subset for input wouldn't work out. Regardless, they've apparently chosen not to engage and that's their prerogative. I don't want to put words in anyone's mouth though; if I'm misinterpreting then I'm glad to hear more on the subject.

What I would argue is that the problem with the AsYouType formatter as it's being applied in intl-tel-input is not with the component itself, but with the data set it's operating on. The widget is clearly built to be metadata-driven, and concerns with specific formats can be cleanly and thoroughly addressed by removing those formats from the metadata file that it's compiled with. I don't think it's in any way an abuse of the formatter or broader library in the context of intl-tel-input to deploy only a subset of its metadata. It might be presumptuous to assume that we can identify all problem formats in an automated way without formal support for that interpretation by libphonenumber (though I suspect we can make a reasonable guess), but if someone seeking an E.164 result wants to remove known problem formats, then I don't see anything wrong with it aside from the hassle of maintaining those curated changes through releases of libphonenumber.

The as-you-type formatting capability adds some complexity and weight to intl-tel-input, but it enables support for unified extension input, and I think it's one of the distinguishing features of the widget. Libphonenumber is amazing as an abstract resource, but seeing it brought to life in intl-tel-input is just awesome, and the way the formatter works, when it works, is a real delight. I think it has practical value for the user as well, particularly for line-of-business situations where the user may not be familiar with the format of numbers in the country in question. I agree that the UX problem of unwanted formats causing confusion is a serious one, but I've been able to address that satisfactorily so far by just removing those formats in the build that I use. Nothing's going to prevent anyone who likes and depends on these features from forking and continuing to maintain libphonenumber releases on their own branch, but I think the library is stronger with them if there's a reasonable solution for restricting the formats.

@jackocnr
Copy link
Owner Author

Thank you for taking the time to write that. It's very encouraging to have someone feel so strongly about it. If we have people like you who are willing to put in the time to make this work, and we write a lot of tests to protect ourselves, then I think I would feel comfortable keeping autoFormat for now :)

@jackocnr jackocnr changed the title Disable and remove autoFormat feature Disable and remove formatAsYouType feature Feb 5, 2016
@jackocnr jackocnr changed the title Disable and remove formatAsYouType feature Disable and remove autoFormat feature Feb 5, 2016
@jackocnr
Copy link
Owner Author

jackocnr commented Feb 5, 2016

As per my comment here, I have decided to remove the autoFormat feature until either libphonenumber decides to support our use case for their AsYouTypeFormatter (that would mean 1. formatting from the first digit instead of waiting until the third, and 2. allowing an option to specify the desired format e.g. full international format), or we find another lib that does the job.

This libphonenumber issue is about specifying a format: https://github.com/googlei18n/libphonenumber/issues/907

And this one talks about the 3 digit minimum: https://github.com/googlei18n/libphonenumber/issues/527

@jackocnr
Copy link
Owner Author

Implemented this change in v8.0.0.

RIP autoFormat <3

@avimar
Copy link

avimar commented Feb 13, 2016

I'm sad to see this leave.. I thought this was an awesome bit of functionality.

@jackocnr
Copy link
Owner Author

Yes I'm sad too. But I've just done a bit more research, and it was actually broken for 49 countries including the USA. Here's the list (when nationalMode=true and numberType=FIXED_LINE, these countries' placeholder started with an open parenthesis, which the user couldn't type):

American Samoa: (684) 622-1234
Anguilla: (264) 461-2345
Antigua and Barbuda: (268) 460-1234
Armenia (Հայաստան): (010) 123456
Australia: (02) 1234 5678
Azerbaijan (Azərbaycan): (012) 312 34 56
Bahamas: (242) 345-6789
Barbados: (246) 412-3456
Bermuda: (441) 234-5678
Brazil (Brasil): (11) 2345-6789
British Virgin Islands: (284) 229-1234
Canada: (204) 234-5678
Cayman Islands: (345) 222-1234
Chile: (2) 2123 4567
Christmas Island: (08) 9164 1234
Cocos (Keeling) Islands: (08) 9162 1234
Colombia: (1) 2345678
Cuba: (07) 1234567
Dominica: (767) 420-1234
Dominican Republic (República Dominicana): (809) 234-5678
Ecuador: (02) 212-3456
Grenada: (473) 269-1234
Guam: (671) 300-1234
Hungary (Magyarország): (1) 234 5678
Indonesia: (061) 2345678
Ireland: (022) 12345
Jamaica: (876) 512-3456
Jordan (‫الأردن‬‎): (06) 200 1234
Lithuania (Lietuva): (8-312) 34567
Montserrat: (664) 491-2345
Northern Mariana Islands: (670) 234-5678
Pakistan (‫پاکستان‬‎): (021) 23456789
Paraguay: (21) 2345678
Peru (Perú): (01) 1234567
Philippines: (02) 123 4567
Puerto Rico: (787) 234-5678
Saint Kitts and Nevis: (869) 236-1234
Saint Lucia: (758) 430-5678
Saint Vincent and the Grenadines: (784) 266-1234
Sierra Leone: (022) 221234
Sint Maarten: (721) 542-5678
Slovenia (Slovenija): (01) 123 45 67
Tajikistan: (8) 372 12 3456
Trinidad and Tobago: (868) 221-1234
Turkey (Türkiye): (0212) 345 6789
Turkmenistan: (8 12) 34-56-78
Turks and Caicos Islands: (649) 712-1234
U.S. Virgin Islands: (340) 642-1234
United States: (201) 555-5555

@jackocnr
Copy link
Owner Author

Oh and one more note for people reading this thread: one alternative is to use the formatNumber method (provided by utils.js) to format the number on blur.

@slavafomin
Copy link
Contributor

Hello!

I just wanted to say, that we are extremely disappointed and frustrated that you've decided to drop the support for phone number formatting. For us, this is the most useful feature of the intl-tel-input plugin, without it it's value is limited.

Actually, I'm not sure I can see the rational ground for this decision. As you stated in the documentation intl-tel-input support approximately 230 countries. The problem is experienced for just 49 of them. It's just a 21% of the total amount of affected users. In terms of population this number is probably even lesser. We are using this library for CIS countries which almost not affected at all. It works perfectly fine for Russian telephone numbers and our user base is 90% Russian right now.

I can't comprehend why you've decided to remove the entire feature when only 20% of users are affected. Wouldn't it be much smarter to just disable this feature for only affected countries?

The intl-tel-input is probably the best and only such UI library in the world right now, that perfectly solves the problem of entering correct phone numbers. We highly appreciate all your effort in developing and maintaining it. However, we've already spent a lot of our own time in order to integrate it into our new big project. I even created an integration library for Angular.js myself. It's a huge pain for me to see such a good and perfectly working plugin (for our users at least) to become crippled like this. And I'm appealing to you in order to find working solution to the problem instead of throwing the baby out with the bathwater.

1). Is it possible to disable this feature for only affected countries and preserve it for others?

2). If you really want to remove this functionality from the core package maybe we can re-introduce it as additional plugin? I.e. implement an extensible interface and use it to add this feature back. That way, the developers which wanted to have this functionality can have it by installing the additional JavaScript-file (even from remote repository).

We are very concerned with this problem and would really like to find a way to save this feature.

Thank you!

@jackocnr
Copy link
Owner Author

@slavafomin first off, let me join you in lamenting the loss of this feature - I put a lot of time and effort into it and trust me it was a difficult decision to remove it.

Regarding your suggestion to disable the feature just for the 49 broken countries - unfortunately that is not the only problem. It is broken for all countries on certain browsers, and for certain native events, and then there's the fact that the implementation is fundamentally a hack on an external lib who's maintainers have explicitly advised us against using it this way!

If you want to work on an additional plugin that adds this functionality then that's up to you, but as for having it in core: either we find a way to fix it for all countries (ideas welcome), or we leave it out.

@slavafomin
Copy link
Contributor

I'm sorry I'm not sure how it's all working together. What exactly are we using from Google's library? I do believe it's data and formatting logic. What if we extract the required data from the original database and then implement the formatting logic ourselves? What's your estimate on this would it be hard to implement?

@nlwillia
Copy link

The asyoutypeformatter is here. As you can see, it's not a trivial component. My suggestion was to just modify the metadata it runs off of to get rid of unwanted variations. That turned out to be fairly effective, but there was still a lag problem where it wouldn't immediately accept or recognize the example format displayed in the placeholder text until the user had typed a few raw digits. The owner (who is entitled to his opinion) decided to draw the line there, and here we are.

v8 is a breaking change that I don't have time to address in my own application right now, so I'll be maintaining a v7 fork with the mitigations described in my PR for the short term. Unless we see an official solution from the libphonenumber side (which doesn't seem likely), a separate plugin project may be the best long term approach. It would have to maintain its own utils.js which is unfortunate, but there's no reason it couldn't bolt as-you-type and extension behaviors back on with keyboard events as long as you're tolerant of some edge cases.

@jackocnr
Copy link
Owner Author

@slavafomin we use a custom build of Google's libphonenumber for formatting/validation/placeholder numbers, which you can read about here: https://github.com/jackocnr/intl-tel-input/blob/master/src/js/utils.js.

@nlwillia has been very helpful in discussing this issue with me and coming up with ideas to try and get the autoFormat feature working properly for everyone (for which I am very grateful). Some of our discussion/ideas in this pull request: #357

If you guys have any questions about how anything works, or if you want to discuss any ideas, feel free to reach out. I would be thrilled if you found a reliable way to make this work for everyone!

Yer I think a separate project focusing on the utils.js file would be valuable. One that either found some clever way to manipulate libphonenumber to do what we need, or one that just copied the logic and then was maintained in-house.

@caseyjhol
Copy link
Contributor

Yes I'm sad too. But I've just done a bit more research, and it was actually broken for 49 countries including the USA. Here's the list (when nationalMode=true and numberType=FIXED_LINE, these countries' placeholder started with an open parenthesis, which the user couldn't type):

I personally think this was more a problem with the placeholder, than the actual autoFormat feature itself. I completely removed the placeholder in my implementation in June of last year, for this same reason - the placeholder implied that you could type parenthesis and dashes.

I really don't think we need the placeholder (Google doesn't use one), especially if having it requires such a massive change. I'd prefer to keep autoFormat implemented, but simply hide the placeholder if it is enabled (or something as simple as "10 digits" so the user knows how many numbers to type).

I was deep in another project when these discussions were going on, otherwise I would've weighed in sooner. This just seems like a major change that's going to create a lot of extra work for many of the developers who use this plugin, to fix what is (as far as I can see), a pretty minor problem.

@jackocnr
Copy link
Owner Author

@caseyjhol thanks for weighing in. I really appreciate hearing everyone's opinions.

Regarding your suggestion to disable the placeholder: it's a matter of taste - I personally think placeholders are very useful. And removing the placeholder wouldn't solve the problem anyway - a lot of people will still try to type an open parenthesis as the first character and get a red flash, which is still bad UX.

Then there's all the other points I raised in my first comment e.g. hacking libphonenumber (which makes it unsupported and bug-prone), broken native events, unsupported in some browsers, other bugs, and a lot of people's opinions (including my own, and Google's for that matter) that you should not restrict what the user can type in an input - it's unexpected and can create a bad experience.

@kirkas
Copy link

kirkas commented Feb 18, 2016

The only question that should matter for autoFormat (or any feature) is: How does it affect and improve the user experience?

Let's review:

  • It doesn't work properly for 20% of users (and potentially waaaay more since US is in that list).
  • Users are humans, and humans are intrinsically unique: They will type (555) 555 555, (555)-555-555, 555555555, 555.555.5555, +1 555-555-555. There is no organic and global pattern (unlike with credit card numbers). Enforcing one format ensures the frustration of many.
  • Updating value while typing is not considered a good UX:

Ideally you'd let them type in the phone number in any format, and you'd have client and server side logic that could parse it out.

Link

Do not update what users enter when they're still typing. It fuddles up their ability to edit as they type, and it makes the field a moving target.

Link

@lucasbmenezes
Copy link

is there any example on how to use formatNumber from utils.js?

@avimar
Copy link

avimar commented Mar 29, 2016

@lucasbmenezes

This code was based on riotjs but it should give you the idea:

var telInput =$('#number');
telInput.blur(function() {
    var currentFormat = (self.number.value[0]==="+") ? intlTelInputUtils.numberFormat.INTERNATIONAL : intlTelInputUtils.numberFormat.NATIONAL;
    self.number.value = telInput.intlTelInput("getNumber",currentFormat);
    }

The currentFormat part checks if INTL/NTL format and leaves the number in that format.
I have it only work on Blur since format-as-you-type is MUCH more complicated.

@lxraysor lxraysor mentioned this issue Sep 22, 2017
@janakad
Copy link

janakad commented Oct 13, 2017

How to get country with double zeroes?

@edgardluz
Copy link

Another vote for restoring this feature some how. 99% of usage on my apps are US only. I'd love to use this plugin but auto-formatting is a must 👍

@chatis
Copy link

chatis commented Dec 16, 2017

It could help someone,

I use the jQuery Plugin MASK for doing that.. and working very well
you can find the plugin here : http://digitalbush.com/projects/masked-input-plugin

I use my code like this

$(".tel").intlTelInput({
	  autoHideDialCode: false,
	  autoPlaceholder : 'aggressive',
	  initialCountry : 'CH',
	  preferredCountries : ['CH', 'FR', 'DE', 'IT', 'CA'],
	  separateDialCode : true,
  });
  
var telInput = $(".tel");
	  
var reset = function() {
  telInput.removeClass("error");
  $("#tel_error").css("background", "url(../image_site/cross.png) no-repeat 10px 9px");
};

// on blur: validate
telInput.blur(function() {
  reset();
  if ($.trim(telInput.val())) {
    if (telInput.intlTelInput("isValidNumber")) {
      $("#tel_error").css("background", "url(../image_site/check.png) no-repeat 10px 9px");
    } else {
	    $("#tel_error").css("background", "url(../image_site/cross.png) no-repeat 10px 9px");
    }
  }
});

telInput.on("countrychange", function(e, countryData) {
	$("#dial").val("+"+countryData.dialCode);
	$(".tel").val('');
	$(".tel").mask($(this).attr('placeholder').replace(/[0-9]/g, "9"));
});

@hmzlam
Copy link

hmzlam commented Jul 18, 2019

i prefer to not use hacked libphonenumber
after initiate your intl-tel-input

just use cleave js

var cleave = new Cleave('#telephone', {
		phone: true,
		phoneRegionCode: 'FR'
	});

@multiwebinc
Copy link

multiwebinc commented Mar 5, 2020

Here's the code @chatis provided above without jQuery since the library no longer requires it:

const telInput = document.querySelector("#telInput");

var iti = window.intlTelInput(telInput, {
      utilsScript: "/js/intl-tel-input/utils.js",
      preferredCountries: ['AU'],
      nationalMode: false,
      formatOnDisplay: true // SET THIS!!!
    }
);

telInput.addEventListener('keyup', formatIntlTelInput);
telInput.addEventListener('change', formatIntlTelInput);

function formatIntlTelInput() {
    if (typeof intlTelInputUtils !== 'undefined') { // utils are lazy loaded, so must check
        var currentText = iti.getNumber(intlTelInputUtils.numberFormat.E164);
        if (typeof currentText === 'string') { // sometimes the currentText is an object :)
            iti.setNumber(currentText); // will autoformat because of formatOnDisplay=true
        }
    }
}

@sriramgroot
Copy link

Here's the code @chatis provided above without jQuery since the library no longer requires it:

const telInput = document.querySelector("#telInput");

var iti = window.intlTelInput(telInput, {
      utilsScript: "/js/intl-tel-input/utils.js",
      preferredCountries: ['AU'],
      nationalMode: false,
      formatOnDisplay: true // SET THIS!!!
    }
);

telInput.addEventListener('keyup', formatIntlTelInput);
telInput.addEventListener('change', formatIntlTelInput);

function formatIntlTelInput() {
    if (typeof intlTelInputUtils !== 'undefined') { // utils are lazy loaded, so must check
        var currentText = iti.getNumber(intlTelInputUtils.numberFormat.E164);
        if (typeof currentText === 'string') { // sometimes the currentText is an object :)
            iti.setNumber(currentText); // will autoformat because of formatOnDisplay=true
        }
    }
}

Thanks @multiwebinc it worked for me

@s-o-f
Copy link

s-o-f commented Aug 20, 2021

Here's the code @chatis provided above without jQuery since the library no longer requires it:

const telInput = document.querySelector("#telInput");

var iti = window.intlTelInput(telInput, {
      utilsScript: "/js/intl-tel-input/utils.js",
      preferredCountries: ['AU'],
      nationalMode: false,
      formatOnDisplay: true // SET THIS!!!
    }
);

telInput.addEventListener('keyup', formatIntlTelInput);
telInput.addEventListener('change', formatIntlTelInput);

function formatIntlTelInput() {
    if (typeof intlTelInputUtils !== 'undefined') { // utils are lazy loaded, so must check
        var currentText = iti.getNumber(intlTelInputUtils.numberFormat.E164);
        if (typeof currentText === 'string') { // sometimes the currentText is an object :)
            iti.setNumber(currentText); // will autoformat because of formatOnDisplay=true
        }
    }
}

Thanks @multiwebinc it worked for me

Be careful. This will not work with nationalMode: true.
Example:
Enter phone number: +79111188888 (can be copy-pasted)
Try to erase last digit (press backspace)
out

@jackocnr
Copy link
Owner Author

jackocnr commented Jan 16, 2024

It's back baby! 🎈

formatAsYouType released in v19.1.0, and now live on the demo site for you to play with.

I thought of a workaround for the issue where the placeholder number in the US (and other countries) starts with an open bracket, but then it wont let the user type that character first. Annoyingly this is (still!) an issue with libphonenumber, as for some reason they auto-format the number differently to that (just hyphens until you hit 8 digits - don't ask!). BUT my workaround is this: if the user does decide to type their own formatting chars (e.g. an opening bracket), then we simply disable auto-formatting for them. I figure if they want to type their own formatting chars then let them. Or if they don't want to bother then we'll do it for them.

In general, this approach of allowing the user to type whatever they want solves a lot of the concerns I raised before, as we're not preventing the user from doing anything. Also we're no longer calling preventDefault so we're not swallowing any useful events that devs may be relying on.

One factor in re-adding this feature after so long is that I have started to see it be used by the big players e.g. Stripe (more info in this comment), and also Google Contacts (who do something similar to us - if the user types a formatting char, they just disable auto-format).

Also since I see so many people hacking this together themselves in ways that will be super buggy (e.g. by calling getNumber and setNumber on keyup, as above, or by using some third-party masking plugin, generating a mask for each country based on the example number, which is a massive oversimplification and will lead to all sorts of problems), I thought better to offer something official which while not perfect, will provide a much better UX.

Feedback is appreciated, though please start a new issue if you find anything.

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

No branches or pull requests