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

When I set an initialValue to pre-select local country code, if I change the country code, enter a number and validate, country code is restored to initial value #155

Closed
sarbogast opened this issue Dec 25, 2020 · 10 comments

Comments

@sarbogast
Copy link
Contributor

Describe the bug

I have a screen that looks like this:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:intl_phone_number_input/intl_phone_number_input.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
        // This makes the visual density adapt to the platform that you run
        // the app on. For desktop platforms, the controls will be smaller and
        // closer together (more dense) than on mobile platforms.
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  PhoneNumber _phoneNumber;
  bool _verifyingPhoneNumber = false;

  Future<void> _validatePhoneNumber() async {
    if (_formKey.currentState.validate()) {
      _formKey.currentState.save();
      setState(() {
        _verifyingPhoneNumber = true;
      });
      print(_phoneNumber.toString());
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(32.0),
          child: Form(
            key: _formKey,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Expanded(
                  child: InternationalPhoneNumberInput(
                    isEnabled: !_verifyingPhoneNumber,
                    onInputChanged: (value) {
                      _phoneNumber = value;
                    },
                    initialValue: PhoneNumber(
                      isoCode: Platform.localeName.split('_').last,
                    ),
                    autoFocus: true,
                    selectorConfig: SelectorConfig(
                      selectorType: PhoneInputSelectorType.DIALOG,
                      countryComparator: (country1, country2) {
                        return country1.name.compareTo(country2.name);
                      },
                      useEmoji: true,
                    ),
                  ),
                ),
                Row(
                  children: [
                    Container(
                      width: 44.0,
                      height: 44.0,
                      child: RawMaterialButton(
                        shape: CircleBorder(),
                        child: _verifyingPhoneNumber
                            ? CircularProgressIndicator(
                                valueColor: AlwaysStoppedAnimation<Color>(
                                  Theme.of(context).colorScheme.onSecondary,
                                ),
                              )
                            : Icon(
                                Icons.arrow_forward_ios,
                                color:
                                    Theme.of(context).colorScheme.onSecondary,
                              ),
                        fillColor: Theme.of(context).colorScheme.secondary,
                        onPressed:
                            _verifyingPhoneNumber ? null : _validatePhoneNumber,
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

As you can see, I use initialValue to set a starting country code that corresponds to the region the phone is in. But it the user selects a different country code, inputs a number and clicks the button to call the _validatePhoneNumber() function, the phone number I get is correct but the country code selector is reset back to the one of the initialValue.

I think it has to do with the condition in didUpdateWidget(InternationalPhoneNumberInput oldWidget) but I don't understand enough about the internal logic of this widget to mess with it.

This makes the user think that the wrong phone number with the wrong country code might have been submitted and it's not good. I tested the code above in a brand new Flutter project and it's enough to reproduce the bug.

Package version
0.5.2+2

Flutter version
Stable 1.22.5

To Reproduce
Simply insert the code above in a brand new flutter project with the intl_phone_number_input: ^0.5.2+2 dependency
Run it, choose a different country code from the default one, type a phone number and click the button is the bottom left corner.
Observe the country code selector reset.

Expected behavior
Country code selector should not be modified by validation

** Targeted platforms (please complete the following information):**

  • Both Android and iOS
  • Did not test on web
natintosh added a commit that referenced this issue Dec 26, 2020
…o initialValue after updating/changing value
@natintosh
Copy link
Owner

@sarbogast I just fixed the issue, I really hope this fix works. Thanks for the effort you took to explain this bug, it helped a lot. 🔥🔥🔥

@sarbogast
Copy link
Contributor Author

@natintosh I see that you released a version 0.6.0 that's documented to include every fix since October 14th but I don't think this fix is included for example. And when I compare build 0.5.2+2 and 0.6.0 there are no differences.

@sarbogast
Copy link
Contributor Author

In any case, this bug is back.

@natintosh
Copy link
Owner

Yeah, apologies on that. I did actually fixed it then I saw another bug from the fix which I also had to fix, that likely revert it. I do have a temporary solution that you could use though. Declare this

            PhoneNumber(
                      isoCode: Platform.localeName.split('_').last,
            )

as a field variable and pass the variable as the initial value, that should work.

The problem has to do with the hash value the code generates each time a new PhoneNumber is initialized. But, the widgets rebuild whenever you validate the form, it reinitializes a new PhoneNumber object and that causes this issue.

@natintosh natintosh reopened this Dec 31, 2020
@sarbogast
Copy link
Contributor Author

I don't get it. That's what I am already doing, the problem is that the field comes back to that initial value when I validate the form.

@natintosh
Copy link
Owner

Here is an illustration of what I was trying to tell

Screenrecorder-2020-12-31-18-12-13-915_0_COMPRESSED.mp4
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:intl_phone_number_input/intl_phone_number_input.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
        // This makes the visual density adapt to the platform that you run
        // the app on. For desktop platforms, the controls will be smaller and
        // closer together (more dense) than on mobile platforms.
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  PhoneNumber _phoneNumber;
  bool _verifyingPhoneNumber = false;

  Future<void> _validatePhoneNumber() async {
    if (_formKey.currentState.validate()) {
      _formKey.currentState.save();
      setState(() {
        _verifyingPhoneNumber = true;
      });
      print(_phoneNumber.toString());
    }
  }
---------------------------------------------------------------------
  PhoneNumber number =
      PhoneNumber(isoCode: Platform.localeName.split('_').last);
-----------------------------------------------------------------------
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(32.0),
          child: Form(
            key: _formKey,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Expanded(
                  child: InternationalPhoneNumberInput(
                    isEnabled: !_verifyingPhoneNumber,
                    onInputChanged: (value) {
                      _phoneNumber = value;
                    },
-----------------------------------------------------
                    initialValue: number,
-----------------------------------------------------
                    autoFocus: true,
                    selectorConfig: SelectorConfig(
                      selectorType: PhoneInputSelectorType.DIALOG,
                      countryComparator: (country1, country2) {
                        return country1.name.compareTo(country2.name);
                      },
                      useEmoji: false,
                    ),
                  ),
                ),
                Row(
                  children: [
                    Container(
                      width: 44.0,
                      height: 44.0,
                      child: RawMaterialButton(
                        shape: CircleBorder(),
                        child: Icon(
                          Icons.arrow_forward_ios,
                          color: Theme.of(context).colorScheme.onSecondary,
                        ),
                        fillColor: Theme.of(context).colorScheme.secondary,
                        onPressed: _validatePhoneNumber,
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

In the sample code above, the initial value is set to a field variable call number and from the recording the selected value/country does not reset.

@sarbogast
Copy link
Contributor Author

Ah indeed it works.

@natintosh
Copy link
Owner

natintosh commented Dec 31, 2020

I'm glad it works. Thank you once again.

I'll be closing this now, feel free to reach out if you run into any issue or have a new feature.

@iampapagray
Copy link

iampapagray commented Apr 11, 2022

@natintosh I have a similar problem and the fix above doesnt solve my issue.
I use
String locale = Platform.localeName.split('_').last;
PhoneNumber number = PhoneNumber(isoCode: (locale == 'US') ? locale : '');
to set the initialValue .

i first tried using only PhoneNumber number = PhoneNumber(isoCode: Platform.localeName.split('_').last); but what happened was that it set the country to the locale set in the device. and if the user moved between countries and haven't changed their locale on the device, the country gets stuck at the old country and is unable to change (Switches to the locale country).

i have not tested this on an android device but this bug happens on iOS

7b0d25ef-efb7-4c7e-946b-0bef0dbb94b2.MOV

.

@gitadam0
Copy link

@natintosh I have a similar problem and the fix above doesnt solve my issue. I use String locale = Platform.localeName.split('_').last; PhoneNumber number = PhoneNumber(isoCode: (locale == 'US') ? locale : ''); to set the initialValue .

i first tried using only PhoneNumber number = PhoneNumber(isoCode: Platform.localeName.split('_').last); but what happened was that it set the country to the locale set in the device. and if the user moved between countries and haven't changed their locale on the device, the country gets stuck at the old country and is unable to change (Switches to the locale country).

i have not tested this on an android device but this bug happens on iOS

7b0d25ef-efb7-4c7e-946b-0bef0dbb94b2.MOV
.

Same problem any solution???

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

4 participants