Description
Is there an existing issue for this?
- I have searched the existing issues
Package/Plugin version
9.2.1
Platforms
- Android
- iOS
- Linux
- MacOS
- Web
- Windows
Flutter doctor
Flutter doctor
[√] Flutter (Channel stable, 3.19.6, on Microsoft Windows [Version 10.0.22631.3447], locale en-IN)
• Flutter version 3.19.6 on channel stable at C:\src\flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 54e66469a9 (2 weeks ago), 2024-04-17 13:08:03 -0700
• Engine revision c4cd48e186
• Dart version 3.3.4
• DevTools version 2.31.1
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
• Android SDK at C:\Users\Nipun Shah\AppData\Local\Android\sdk
• Platform android-33-ext4, build-tools 33.0.1
• Java binary at: C:\Program Files\Android\Android Studio\jbr\bin\java
• Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-10027231)
• All Android licenses accepted.
[√] Chrome - develop for the web
• Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe
[X] Visual Studio - develop Windows apps
X Visual Studio not installed; this is necessary to develop Windows apps.
Download at https://visualstudio.microsoft.com/downloads/.
Please install the "Desktop development with C++" workload, including all of its default components
[√] Android Studio (version 2022.3)
• Android Studio at C:\Program Files\Android\Android Studio
• Flutter plugin can be installed from:
https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 17.0.6+0-b2043.56-10027231)
[√] IntelliJ IDEA Community Edition (version 2022.3)
• IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2022.3.1
• Flutter plugin can be installed from:
https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
https://plugins.jetbrains.com/plugin/6351-dart
[√] VS Code (version 1.87.2)
• VS Code at C:\Users\Nipun Shah\AppData\Local\Programs\Microsoft VS Code
• Flutter extension can be installed from:
https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter
[√] Connected device (3 available)
• Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.22631.3447]
• Chrome (web) • chrome • web-javascript • Google Chrome 115.0.5790.171
• Edge (web) • edge • web-javascript • Microsoft Edge 124.0.2478.67
[√] Network resources
• All expected network resources are available.
! Doctor found issues in 1 category.
Minimal code example
Code sample
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
void main() {
runApp(const MyApp());
}
const kCountryItems = ['India', 'US', 'Japan'];
const kStateItems = [
'Gujarat',
'Rajasthan',
'Punjab',
'Florida',
'California',
'Texas',
'Kinki',
'Shikoku',
'Tohoku'
];
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String? _country = kCountryItems.first;
String? _state = kStateItems.first;
// Can be used later to manipulate fields
final _formKey = GlobalKey<FormBuilderState>();
@override
Widget build(BuildContext context) {
const gap = SizedBox(height: 12);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Container(
width: 300,
color: Colors.blue.shade100,
padding: const EdgeInsets.all(12),
child: FormBuilder(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Form'),
gap,
CountryInput(
initialValue: _country,
onChanged: _onCountryChanged,
),
gap,
StateInput(
// ? Enforcing state input to reset/recreate asa `_country` changes
key: ValueKey(_country),
initialValue: _state,
onChanged: _onStateChanged,
),
gap,
],
),
),
),
),
);
}
void _onCountryChanged(String? country) {
setState(() {
_country = country;
// ?? Eventhough state is made null & we used ValueKey() for StateInput to force recreation, it will retain old value !!
_state = null;
print('(: Country Changed > C:- $_country S:- $_state');
});
}
void _onStateChanged(String? state) {
_state = state;
print('(: State Changed > $_state');
}
}
class CountryInput extends StatelessWidget {
const CountryInput({super.key, this.initialValue, required this.onChanged});
static String id = 'country';
final String? initialValue;
final ValueChanged<String?> onChanged;
@override
Widget build(BuildContext context) {
return FormBuilderField<String>(
name: CountryInput.id,
initialValue: initialValue,
builder: (field) => _buildField(field),
onChanged: onChanged,
);
}
Widget _buildField(FormFieldState<String> field) {
return DropdownMenu(
width: 250,
initialSelection: field.value,
onSelected: (value) {
field.didChange(value);
},
dropdownMenuEntries: kCountryItems
.map((e) => DropdownMenuEntry<String>(value: e, label: e))
.toList());
}
}
class StateInput extends StatelessWidget {
const StateInput({super.key, this.initialValue, required this.onChanged});
static String id = 'state';
final String? initialValue;
final ValueChanged<String?> onChanged;
@override
Widget build(BuildContext context) {
return FormBuilderField<String>(
name: StateInput.id,
initialValue: initialValue,
builder: (field) => _buildField(field),
onChanged: onChanged,
);
}
Widget _buildField(FormFieldState<String> field) {
return DropdownMenu(
width: 250,
initialSelection: field.value,
onSelected: (value) {
field.didChange(value);
},
dropdownMenuEntries: kStateItems
.map((e) => DropdownMenuEntry<String>(value: e, label: e))
.toList());
}
}
Current Behavior
FormBuilderField : widget whenever coerced/forced to be recreated (ie maybe via ValueKey or UniqueKey), it's retaining the previous field's value.
Given that
name
parameter remains unchanged before & after forced recreation
In above code example
- The initial value for
CountryInput = India
&StateInput = Gujarat
- StateInput retains value = Gujarat even when CountryInput is changed
NOTE: here StateInput holds
key = ValueKey(_country), hence it will be recreated.
Expected Behavior
FormBuilderField : widget whenever coerced/forced to be recreated (ie maybe via ValueKey or UniqueKey), it should respect & attain the latest field's initial value rather than prioritizing the previous (stale) field's value,
Given that latest field's
name
= old field'sname
.
In above code example
- The initial value for
CountryInput = India
&StateInput = Gujarat
- Whenever CountryInput is changed, StateInput must reset & hence no selected value (ie
_state = null
)
i.eCountryInput = 'Japan'
&StateInput = ''
NOTE: here StateInput holds
key = ValueKey(_country)
, hence it will be recreated; thus current value of_state
(i.e null) should be considered as an initial value for the latest StateInput field.
Steps To Reproduce
- Provide some initial value to your
FormBuilderField
(let say initialValue = 'Gujarat') - Try to change value of initialVal variable holder to null
- Try to forcefully recreate your
FormBuilderField
widget or any of it's ancestor. (for an instance, you can use UniqueKey)
[With above sample code]
- create flutter project
- add dependency ->
flutter_form_builder: ^9.2.1
don't forget to do
flutter pub get
- copy paste aforementioned sample code into main.dart
- run the project
Initially selected value => Country = India & State = Gujarat
- Try to change the country by tapping CountryInput DropDownMenu
You will observe that StateInput still holds Gujarat.
Aditional information
Below is my console snippet when I followed above steps to reproduce
(: Country Changed > C:- US S:- null
Warning! Replacing duplicate Field for state -- this is OK to ignore as long as the field was intentionally replaced
Warning! Ignoring Field unregistration for state -- this is OK to ignore as long as the field was intentionally replaced