I’m trying to fetch the names of countries from an API and display it in a drop-down box. I’m using the bloc library for state management.
Here’s my Code.
select_input_field.dart
– Custom wrapper widget for DropdownButtonField
import 'package:flutter/material.dart';
class SelectInputField extends StatelessWidget {
final String label;
final List<String> options;
final TextEditingController controller;
final EdgeInsets padding;
const SelectInputField(this.label, this.options,
{ Key? key,
required this.controller,
this.padding =
const EdgeInsets.only(top: 8, bottom: 8, left: 30, right: 30)})
: super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: padding,
child: DropdownButtonFormField(
decoration: InputDecoration(
labelText: label,
labelStyle: Theme.of(context).textTheme.bodyMedium,
border: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColorDark,
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).primaryColorDark,
width: 1,
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).colorScheme.secondary,
width: 1,
),
),
fillColor: Theme.of(context).primaryColorLight),
style: Theme.of(context).textTheme.bodyMedium,
items: options.map((String value) {
print(value);
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? value) {
controller.text = value ?? '';
},
),
);
}
}
This is the method I’m using to build it.
Widget _countriesDropDown(BuildContext context, TextEditingController controller){
return BlocProvider(
create: (context) => _signupBloc,
child: BlocBuilder<SignupBloc,SignupState>(
buildWhen: ((previous, current) => previous is! Loaded && current is Loaded),
builder: (context, state){
if (state is Initial){
_signupBloc.add(LoadEvent());
}
else if (state is Loaded){
countries = state.countries;
return SelectInputField("Country", countries, controller: controller);
}
return CircularProgressIndicator(color: Theme.of(context).colorScheme.secondary,);
},
)
);
}
And my bloc class is as follows.
class SignupBloc extends Bloc<SignupEvent, SignupState> {
static const String countriesUrl = "https://api.first.org/data/v1/countries";
SignupBloc() : super(Initial()) {
on<LoadEvent>((event, emit) async{
emit(Loading());
List<String> countries = [];
try{
final response = await http.get(Uri.parse(countriesUrl));
if(response.statusCode == 200){
var responseJson = jsonDecode(response.body);
responseJson['data'].values.forEach((element) {
countries.add(element['country']);
});
emit(Loaded(countries));
}
else{
emit(Failed("Error in getting data"));
}
}
catch(e){
print(e);
emit(Failed("Failed to access internet. Try again later!"));
}
});
}
The error appears to look like this. I cannot understand where this error occurs
======== Exception caught by rendering library =====================================================
The following assertion was thrown during paint():
Tried to paint a RenderObject reentrantly.
The following RenderObject was already being painted when it was painted again: RenderPointerListener#c100e relayoutBoundary=up20 NEEDS-PAINT
... needs compositing
... parentData: <none> (can use size)
... constraints: BoxConstraints(0.0<=w<=351.4, 0.0<=h<=Infinity)
... size: Size(351.4, 64.0)
... behavior: opaque
... listeners: down, panZoomStart
Since this typically indicates an infinite recursion, it is disallowed.
The relevant error-causing widget was:
DropdownButtonFormField<String> DropdownButtonFormField:file:///D:/Projects/sem5/iblock/lib/widgets/forms/select_input_field.dart:20:14
When the exception was thrown, this was the stack:
#0 RenderObject._paintWithContext.<anonymous closure> (package:flutter/src/rendering/object.dart:2693:9)
#1 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2706:6)
#2 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:239:13)
#3 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
#4 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2796:7)
#5 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:239:13)
#6 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:144:15)
#7 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:2796:7)
I need an explanation about what’s wrong with my code and how to fix this.
Output of flutter doctor
[√] Flutter (Channel stable, 3.3.2, on Microsoft Windows [Version 10.0.22621.608], locale en-US)
• Flutter version 3.3.2 on channel stable at C:flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision e3c29ec00c (3 weeks ago), 2022-09-14 08:46:55 -0500
• Engine revision a4ff2c53d8
• Dart version 2.18.1
• DevTools version 2.15.0
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
• Android SDK at C:UsersISHADAppDataLocalAndroidsdk
• Platform android-32, build-tools 30.0.3
• Java binary at: C:Program FilesAndroidAndroid Studiojrebinjava
• Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
• All Android licenses accepted.
[√] Chrome - develop for the web
• CHROME_EXECUTABLE = C:Program FilesBraveSoftwareBrave-BrowserApplicationbrave.exe
[√] Visual Studio - develop for Windows (Visual Studio Build Tools 2019 16.11.18)
• Visual Studio at C:Program Files (x86)Microsoft Visual Studio2019BuildTools
• Visual Studio Build Tools 2019 version 16.11.32802.440
• Windows 10 SDK version 10.0.19041.0
[√] Android Studio (version 2021.3)
• Android Studio at C:Program FilesAndroidAndroid 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 11.0.13+0-b1751.21-8125866)
[√] IntelliJ IDEA Ultimate Edition (version 2022.2)
• IntelliJ at C:Program FilesJetBrainsIntelliJ IDEA 2022.1.2
• Flutter plugin version 70.2.5
• Dart plugin version 222.4167.21
[√] VS Code (version 1.71.2)
• VS Code at C:UsersISHADAppDataLocalProgramsMicrosoft VS Code
• Flutter extension version 3.48.0
[√] Connected device (3 available)
• Windows (desktop) • windows • windows-x64 • Microsoft Windows [Version 10.0.22621.608]
• Chrome (web) • chrome • web-javascript • unknown
• Edge (web) • edge • web-javascript • Microsoft Edge 105.0.1343.53
! Device DRGGAM5890805202 is not authorized.
You might need to check your device for an authorization dialog.
[√] HTTP Host Availability
• All required HTTP hosts are available
• No issues found!
PS:
I’m not much familiar with Flutter/ bloc library.
3
Answers
Converting the
SelectInputField
to aStatefulWidget
solved the issue. I thinkDropdownButtonFormField
need to be rendered itself upon activities on it. So,StatelessWidget
cannot rerender itself causing this problem.Not sure if you still having this issue but I had a similar issue and I added
isExpanded: true
to my DropdownButtonFormField which resolved the error. My problem was caused by the length of the words in my DropdownMenuItem. When I look at the response of your API call I see some very long names. I could be wrong thoughI got the same issue, and I am able to fix it.
The issue is with the
DropdownButtonFormField
.It should have ‘
value
‘ property.