I have problems with DropdownButton in flutter - flutter

Good morning friends, I am trying to use DropdownButton, it brings me the information but it shows me an error before I bring the information.
I printed the data to verify that it did not come empty and it is effectively bringing the list without any problem
This is the error shown:
enter image description here
This is the code that I am using
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
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(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _mySelection;
final String url = "http://webmyls.com/php/getdata.php";
List data;
Future<String> getSWData() async {
var res = await http
.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
var resBody = json.decode(res.body);
setState(() {
data = resBody;
});
print(data);
return "Sucess";
}
#override
void initState() {
super.initState();
this.getSWData();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new DropdownButton(
//data != null,
isDense: true,
hint: new Text("Select"),
items: data.map((item) {
return new DropdownMenuItem(
child: new Text(item['item_name']),
value: item['id'].toString(),
);
}).toList(),
onChanged: (newVal) {
setState(() {
_mySelection = newVal;
});
},
value: _mySelection,
),
),
);
}
}

Yeimer Initialize data : List data = List(); your issue will be resolved.

Create this widget:
Widget _myDropDown() {
if (data == null) return Center();
return new DropdownButton(
//data != null,
isDense: true,
hint: new Text("Select"),
items: data.map((item) {
return new DropdownMenuItem(
child: new Text(item['item_name']),
value: item['id'].toString(),
);
}).toList(),
onChanged: (newVal) {
setState(() {
_mySelection = newVal;
});
},
value: _mySelection,
);
}
and then put _myDropDown inside your Center

Related

Can't get the futurebuilder data into the dropdownbutton to pick from there

I am trying to get some String data from a server via future builder, which works. Then transfer those strings into the dropdownbutton thing, to show as options then to be picked. I mean they will show up on dropdownbutton. Think of it like, I will choose a person to do a job here, I get the names from a database and show it on screen. So user can choose from there. Here is the important data that supposedly gets the dropdown data from the futurebuilder:
String dropdownValue = _MyAppState.data2.first;
It gives the following error:
Bad state: No element
And here is my code:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
const List<String> list = <String>['One', 'Two', 'Three', 'Four'];
Future<List<Album>> fetchAlbum() async {
final response = await http.get(
Uri.parse('https://my-json-server.typicode.com/fluttirci/testJson/db'));
//this was for testing.
//print(response);
Map<String, dynamic> userMap = jsonDecode(response.body);
if (response.statusCode == 200) {
return (userMap['employees'] as List)
.map((e) => Album.fromJson(e))
.toList();
} else {
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
Album(this.userId, this.id, this.title);
Album.fromJson(Map<String, dynamic> json)
: userId = json['userId'],
id = json['id'],
title = json['title'];
Map<String, dynamic> toJson() => {
'userId': userId,
'id': id,
'title': title,
};
}
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({super.key});
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
late Future<List<Album>> user;
late List<Album> data;
static List<String> data2 = [];
#override
void initState() {
super.initState();
user = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
brightness: Brightness.dark,
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Fetch Data Example'),
),
body: Column(children: <Widget>[
const Expanded(
child: DropdownButtonExample(),
),
Expanded(
child: FutureBuilder<List<Album>>(
future: user,
builder: (context, snapshot) {
if (snapshot.hasData) {
data = snapshot.data ?? [];
return ListView.builder(
itemBuilder: (context, index) {
data2.add(data[index].title);
print('data2 was fetched: ${data2[index]}');
return Column(
children: [
Text(data[index].title),
],
);
},
itemCount: data.length,
);
} else if (snapshot.hasError) {
return Text(
'${snapshot.error}',
);
}
return const Center(
child: CircularProgressIndicator(),
);
},
),
)
]),
),
);
}
}
class DropdownButtonApp extends StatelessWidget {
const DropdownButtonApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text('DropdownButton Sample')),
body: const Center(
child: DropdownButtonExample(),
),
),
);
}
}
class DropdownButtonExample extends StatefulWidget {
const DropdownButtonExample({super.key});
#override
State<DropdownButtonExample> createState() => _DropdownButtonExampleState();
}
class _DropdownButtonExampleState extends State<DropdownButtonExample> {
String dropdownValue = _MyAppState.data2.first;
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String? value) {
// This is called when the user selects an item.
setState(() {
dropdownValue = value!;
});
},
items: list.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
}
}
There are more than one error in your code.
Error 1 :
You are trying to access first element from empty list. At
String dropdownValue = _MyAppState.data2.first;
Actual issue of Bad state: No element
You can give only dropdown items as value. In your case the data coming from api and hardcoded list List<String> list = <String>['One', 'Two', 'Three', 'Four']; both are different.
Hope this helps

How to display data from nested list in Flutter

When I try display data from nested list it gives me that data which is not list at all.
Please help how to get that options data as list and display on Flutter widget.
class QuizData {
List<BrainData> getData = [
BrainData(
questionID: "biology1",
question:
"Pine, fir, spruce, cedar, larch and cypress are the famous timber-yielding plants of which several also occur widely in the hilly regions of India. All these belong to",
options: [
"angiosperms",
"gymnosperms",
"monocotyledons",
"dicotyledons",
],
answer: [false, true, false, false],
),
];
}
From the question, I have created a sample example for you.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Test App',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
List<BrainData> list = [];
var selectedValue;
List<BrainData> getData = [
BrainData(
questionID: "biology1",
question:
"Pine, fir, spruce, cedar, larch and cypress are the famous timber-yielding plants of which several also occur widely in the hilly regions of India. All these belong to",
options: [
"angiosperms",
"gymnosperms",
"monocotyledons",
"dicotyledons",
],
answer: [false, true, false, false],
),
];
#override
void initState() {
super.initState();
setState(() {
list = getData;
});
}
void showInSnackBar(String value, bool isCorrect) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
backgroundColor: isCorrect ? Colors.green : Colors.red,
content: Text(value),
duration: const Duration(milliseconds: 200),
));
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: list.isEmpty
? Container()
: ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
var item = list[index];
return Column(
children: [
Padding(
padding: const EdgeInsets.all(15.0),
child: Text('${index + 1} : ${item.question}'),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: item.options.map((e) {
return RadioListTile(
title: Text(e),
value: e,
groupValue: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value;
var correctAnswerIndex = item.answer.indexWhere((element) => element == true);
var selectedItemIndex =
item.options.indexWhere((element) => element == value);
if (correctAnswerIndex == selectedItemIndex) {
showInSnackBar('Selected Correct Value', true);
} else {
showInSnackBar('Better luck next time', false);
}
});
},
);
}).toList(),
),
)
],
);
}),
);
}
}
class BrainData {
final String questionID;
final String question;
final List<String> options;
final List<bool> answer;
BrainData({
required this.questionID,
required this.question,
required this.options,
required this.answer,
});
}
This is the Sample UI:
Check the example and let me know if it works for you.

How to pass data between Widgets

I've the below code where I fetch correctly data from url, display it in DataTable, and get the idext of the tapped row.
I need to use this index and display the related information on the back of the widget, I cam across TweenAnimationBuilder but not sure how to send data between the 2 faces, or if there is another way to do what I'm looking for:
import 'package:flutter/material.dart';
import 'dart:convert';
import 'dart:io';
import 'dart:async';
import 'package:csv/csv.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage(title: 'Flutter Demo Home Page'),
);
}
}
class HomePage extends StatefulWidget {
HomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_AppState createState() => _AppState();
}
Future<List<List<dynamic>>> fetchUserData() async {
final request = await HttpClient().getUrl(Uri.parse(
'https://docs.google.com/spreadsheets/d/e/2PACX-1vQvf9tp4-fETDJbC-HRmRKvVFAXEAGO4lrYPpVeiYkB6nqqXdSs3CjX0eBMvjIoEeX9_qU6K2RWmzVk/pub?gid=0&single=true&output=csv'));
final response = await request.close();
List<List<dynamic>> rowsAsListOfValues;
await for (final csvString in response.transform(const Utf8Decoder())) {
rowsAsListOfValues = const CsvToListConverter().convert(csvString);
}
return rowsAsListOfValues;
}
class _AppState extends State<HomePage> {
List<List<dynamic>> rowsAsListOfValues;
// ScrollController _controller;
#override
void didChangeDependencies() async {
super.didChangeDependencies();
rowsAsListOfValues = await fetchUserData();
super.setState(() {}); // to update widget data
}
#override
void initState() {
super.initState();
// _controller = ScrollController();
// _controller = new ScrollController()..addListener(_scrollListener);
}
/*
void _scrollListener() {
if (_controller.position.extentAfter <= 0.0 &&
_controller.offset >= _controller.position.maxScrollExtent &&
!_controller.position.outOfRange) {
print("call fetch method again");
}
} */
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
rowsAsListOfValues == null
? Text("Loading data...")
: Text(
'', // $rowsAsListOfValues
),
rowsAsListOfValues == null
? CircularProgressIndicator()
: DataTable(
showCheckboxColumn: false, // <-- this is important
columns: const <DataColumn>[
DataColumn(
label: Text(
'City',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Branches',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: List.generate(rowsAsListOfValues.length - 1, (index) {
return DataRow(
onSelectChanged: (bool selected) {
if (selected) {
print('index-selected: ${rowsAsListOfValues[index + 1][0]}');
}
},
cells: <DataCell>[
// DataCell(Text('${rowsAsListOfValues[index + 1][0]}')), // Index
DataCell(Text('${rowsAsListOfValues[index + 1][1]}')), // city
DataCell(Text('${rowsAsListOfValues[index + 1][2]}')), // branch
],
);
}),
),
],
),
),
);
}
}
May be you can use this https://pub.dev/packages/flippable_box flutter plugin which gives you options to define different view for front and back. You can use _isFlipped variable to maintain which side you want to display.
FlippableBox(
front: Data table for front view,
back: Display selected row,
isFlipped: _isFlipped,
)

capture data from DropDownButton in flutter and send it to the database

I'm new to flutter app development and would like to ask for your help
I already learned to capture the data of a TextFormField but with the DropDownButtons I have no idea how it is I try to use controller to put a name but I get an error
I have a DropDownButton and it works for me, it is loading the list successfully and I would like to know, how to capture the data I select in the DropDownButton and send it to my database
This is the code that I am using:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
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(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _mySelection;
final String url = "http://webmyls.com/php/getdata.php";
List data = List();
Future<String> getSWData() async {
var res = await http
.get(Uri.encodeFull(url), headers: {"Accept": "application/json"});
var resBody = json.decode(res.body);
setState(() {
data = resBody;
});
print(data);
return "Sucess";
}
#override
void initState() {
super.initState();
this.getSWData();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new DropdownButton(
//data != null,
isDense: true,
hint: new Text("Select"),
items: data.map((item) {
return new DropdownMenuItem(
child: new Text(item['item_name']),
value: item['id'].toString(),
);
}).toList(),
onChanged: (newVal) {
setState(() {
_mySelection = newVal;
});
},
value: _mySelection,
),
),
);
}
}
I hope you can help me.
the latest dropdown value is always stores in your _mySelection. So the only thing you should do is to save _mySelection in your database.

Flutter Driver scrolling through dropdown list

I would like to scroll through a drop-down list as part of a flutter driver test, however I can't seem to figure out exactly how I would do this?
I've tried using a ValueKey, and have tried digging through the Flutter Inspector in Intellij as well, but have had no luck thus far.
I have tried find.byType(Scrollable); and it doesn't seem to work even after widgetTester.tap(). Turns out I need to wait for the screen to update with widgetTester.pumpAndSettle()
testWidgets("Test DropdownButton", (WidgetTester widgetTester) async {
await widgetTester.pumpWidget(MyApp())
final dropdownButtonFinder = find.byKey(const ValueKey('DropdownButton')); final dropdownItemFinder = find.widgetWithText(InkWell, 'Item 50'); // find.textContaining() doesn't seem to work
// Tap on the DropdownButton
await widgetTester.tap(dropdownButtonFinder);
await widgetTester.pumpAndSettle(const Duration(seconds: 2));
final dropdownListFinder = find.byType(Scrollable);
expect(dropdownListFinder, findsOneWidget); // Finds Scrollable from tapping DropDownButton
// Scroll until the item to be found appears.
await widgetTester.scrollUntilVisible(dropdownItemFinder, 500.0,
scrollable: dropdownListFinder);
await widgetTester.tap(dropdownItemFinder);
await widgetTester.pumpAndSettle(const Duration(seconds: 2));
// Verify that the item contains the correct text.
expect(find.textContaining('Item 50'), findsOneWidget);
});
Main code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<String> mockList() => List<String>.generate(100, (i) => 'Item $i');
String? dropdownValue;
#override
Widget build(BuildContext context) {
// debugPrint('${foo!}');
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
key: Key('Widget1'),
),
body: Center(
child: DropdownButton(
key: Key('DropdownButton'),
value: dropdownValue,
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: mockList()
.map<DropdownMenuItem<String>>(
(String value) => DropdownMenuItem<String>(
value: value,
child: Text(value),
key: Key('item$value'),
),
)
.toList(),
)
);
}
}
Running the test