intl_phone_number_input icon indicating copy to clipboard operation
intl_phone_number_input copied to clipboard

Error when using PhoneNumberInput initial value in stateful widget

Open hummy123 opened this issue 2 years ago • 3 comments

Hi there,

Describe the bug The bug is that I am not able to change the contents of the input field when the two following conditions are met:

  1. I call setState((){}); in the onChanged parameter, and
  2. I provide initialValue: PhoneNumber(phoneNumber: "+447835201980", isoCode: "GB") to the input field. If I remove either of these conditions, the code works fine.

Package version intl_phone_number_input: ^0.7.0+2

Flutter version 2.10.4

To Reproduce Steps to reproduce the behavior:

  1. Code Snippet
import 'package:flutter/material.dart';
import 'package:intl_phone_number_input/intl_phone_number_input.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var darkTheme = ThemeData.dark().copyWith(primaryColor: Colors.blue);

    return const MaterialApp(
      title: 'Demo',
      home: Scaffold(
        body: MyHomePage(),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final GlobalKey<FormState> formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Center(
      child: InternationalPhoneNumberInput(
        onInputChanged: (PhoneNumber number) {
          setState(() {});
          print("input apparently changed");
          print(number.phoneNumber);
        },
        initialValue: PhoneNumber(
          phoneNumber: "+447862792432",
          isoCode: "GB",
        ),
      ),
    );
  }
}
  1. Use case

My original use case is to have a button that is greyed out (not clickable) based the number's value (like if the phone number is blank) and have it be clickable on other occasions. However

  1. Interaction with the widget

The only interaction with the widget required to see the bug is to try inputting numbers on it with the above code.

  1. See error 5 ...

Expected behavior I expected to be able to input numbers.

Screenshots If applicable, add screenshots to help explain your problem.

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

  • OS [e.g. Android, iOS, ...]
  • I have tested the Android emulator only.
  • Web [✔ or ❌]
  • I have not tested on the web. ❌

Additional context I actually moved my form data to flutter_redux for an easier-to-handle architecture and had the same problem there when wrapping the PhoneNumberInput in a StoreConnector.

However, I managed to patch my way through that bug by using ignoreChange: (_) => true, for the StoreConnector widget directly above the . So it's not an issue for me anymore, but I thought it might be worth filing a bug in case any other person comes across this and the team behind this project think it is worth addressing the setState/initialValue bug.

For reference (in case anyone else comes across this via Google), my working widget with flutter_redux:

import 'package:carrybags_partner_app/redux/app_state/app_state.dart';
import 'package:carrybags_partner_app/redux/form_reducers/profile_form_reducer.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:intl_phone_number_input/intl_phone_number_input.dart';

class ProfileFormPhone extends StatelessWidget {
  const ProfileFormPhone({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ColoredBox(
      color: Colors.white,
      child: StoreConnector<AppState, AppState>(
        ignoreChange: (_) => true,
        onInit: (store) async {
          final String number = store.state.profile.phoneNumber.toString();
          final PhoneNumber tempNum =
              await PhoneNumber.getRegionInfoFromPhoneNumber(number);
          final PhoneNumber phoneNumber =
              store.state.profileForm!.phoneNumber ?? tempNum;
          store.dispatch(setProfileFormPhone(phoneNumber));
        },
        converter: (store) => store.state,
        builder: (context, state) {
          PhoneNumber? phoneNumber = state.profileForm?.phoneNumber ??
              PhoneNumber(
                phoneNumber: state.profile.phoneNumber,
                isoCode: "GB",
              );
          return InternationalPhoneNumberInput(
            onInputChanged: (PhoneNumber phone) {
              final store = StoreProvider.of<AppState>(context);
              store.dispatch(setProfileFormPhone(phone));
            },
            initialValue: PhoneNumber(
              phoneNumber: phoneNumber.phoneNumber,
              isoCode: phoneNumber.isoCode ?? "GB",
            ),
            inputBorder: const OutlineInputBorder(),
            selectorConfig: const SelectorConfig(
              setSelectorButtonAsPrefixIcon: true,
              leadingPadding: 8,
              selectorType: PhoneInputSelectorType.BOTTOM_SHEET,
              useEmoji: true,
            ),
          );
        },
      ),
    );
  }
}

hummy123 avatar Apr 14 '22 09:04 hummy123

I run into the same problem. An easier fix i found was to initialise the PhoneNumber() object in the initState method just once and then just reference it in your build method.

I guess the bug is somehow related by the fact that PhoneNumber() gets reconstructed everytime the build methold is called. Since thats basically what setState is doing.

garlicPasta avatar Apr 27 '22 11:04 garlicPasta

I also found a solution. The way I fixed that was creating a var outside the build method like final initialCountryValue = PhoneNumber(isoCode: Platform.localeName.split('_').last);

After that you pass that as initial value InternationalPhoneNumberInput( onInputChanged: onInputChanged, initialValue: initialCountryValue)

gsouza97 avatar May 19 '23 19:05 gsouza97

The same Issue here I solved this using 2 different vars one of them for just setting the initial value and the other to keep tracking the changed value, but still this issue must be fixed

shehab0717 avatar Sep 20 '23 23:09 shehab0717