I'm trying to populate the drop down by fetching the values from API.
When I click the drop down,the values are being shown,when I try to select a value,following error is thrown
items.isEmpty || value == null || items.where((DropdownMenuItem<T> item) => item.value == value).length == 1': is not true.
values in the list are not empty
When I tried to remove 'value' property of drop down, the error is not shown but the drop down is not showing the selected value
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:something/Utils/formServices.dart';
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
import 'package:intl/intl.dart';
import 'dart:convert';
String insurer;
String package;
List insCat = List();
List insurers = List();
List<DropdownMenuItem> items = [];
class AddOrEditPack extends StatefulWidget{
#override
AddOrEditPackState createState() =>AddOrEditPackState();
}
class AddOrEditPackState extends State<AddOrEditPack>{
final formKey = GlobalKey<FormState>();
String insuranceCategory = ' ';
#override
void initState() {
getCategories();
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Contact Us'),
),
drawer: Drawer(
child: ListView(
children: <Widget>[
ListTile(
title: Text("Home"),
),
],
),
),
body:
Form(
key:formKey,
child: ListView(
children: <Widget>[
Padding(
padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
child: DropdownButtonFormField<String>(
hint:Text('Insurance Category'),
items: insCat.map((item) {
return new DropdownMenuItem<String>(
child: new Text(item['name']),
// value: item['name'],
);
}).toList(),
onChanged: (String newValue) {
setState(() { insuranceCategory = newValue; });
print(newValue);
},
// value: insuranceCategory,
),
),
Padding(
padding: EdgeInsets.fromLTRB(10, 10, 10,0),
child: RaisedButton(
onPressed: () {
contact();
},
child: Text('Submit'),
),
)
],
),
)
),
);
}
getCategories() async{
var resp = await
http.get('http://192.168.4.101:3000/category/getCategoryList');
print(resp.body);
insCat = json.decode(resp.body);
setState(() {
insuranceCategory=insCat[0]['name'];
});
}
}
This is what the API is returning.
[
{"_id":"5d8dad3a2fcb272b7c0e74b5","name":"life insurance"},
{"_id":"5d8dad502fcb272b7c0e74b6","name":"vehicle insurance"},
{"_id":"5d8dadb22fcb272b7c0e74b9","name":"life insurance"}
]
Output:
void main() => runApp(MaterialApp(
title: "Hospital Management",
home: MyApp(),
));
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _mySelection = "2";
final String url = "http://webmyls.com/php/getdata.php";
List data = List(); //edited line
List<DropdownMenuItem> items = [];
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;
items = data.map((item) => DropdownMenuItem(child: Text(item['item_name']), value: item['id'].toString())).toList();
_mySelection = data[0]["id"];
});
print(resBody);
return "Sucess";
}
#override
void initState() {
super.initState();
this.getSWData();
}
#override
Widget build(BuildContext context) {
print("CoolTag: ${data.length}");
return Scaffold(
appBar: AppBar(title: Text("Hospital Management")),
body: Center(
child: DropdownButton(
items: items,
value: _mySelection,
onChanged: (newVal) {
setState(() {
_mySelection = newVal;
});
},
),
),
);
}
}
Related
i am trying to display data list API to dropdown but the result is not there, which i have to fix.
I'm trying to change or update user data and have some data in the form of a list including the user being able to choose country, religion, and others. among these
how do i make it.
fetch API
Future<UserBiodata> getBiodata() async {
String url = Constant.baseURL;
String token = await UtilSharedPreferences.getToken();
final response = await http.get(
Uri.parse(
'$url/auth/mhs_siakad/biodata',
),
headers: {
'Authorization': 'Bearer $token',
},
);
print(response.statusCode);
print(response.body);
if (response.statusCode == 200) {
return UserBiodata.fromJson(jsonDecode(response.body));
} else {
throw Exception('Token Expired!');
}
}
show in widget
String? _mySelection;
List<Agama> agama = [];
#override
void initState() {
super.initState();
BiodataProvider().getBiodata();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(kToolbarHeight),
child: CustomAppbar(
title: 'Edit Biodata',
),
),
body: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.only(left: 12, right: 8),
width: double.infinity,
height: 50,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 1,
blurRadius: 9,
offset: const Offset(
1,
2,
),
),
],
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
items: agama.map((item) {
return DropdownMenuItem<String>(
value: item.nmAgama,
child: Text(item.nmAgama),
);
}).toList(),
onChanged: (newVal) {
setState(() {
_mySelection = newVal!;
});
},
value: _mySelection,
),
),
),
using StateManagement or FutureBuilder to receive async data from Future function (BiodataProvider().getBiodata();)
read more at: https://dart.dev/codelabs/async-await
https://docs.flutter.dev/development/data-and-backend
you are using List<Agama> agama = []; to display the dropdown items, but you are not adding data to your agama list.
So, add the proper data into your agama list which you are getting from API.
And don't forget to do setState((){}) after adding data into agama list because you are not using any state management.
Here is a full example like you want.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter DropDownButton',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: const MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String? dropdownvalue;
Future<List<String>> getAllCategory() async {
var baseUrl = "https://gssskhokhar.com/api/classes/";
http.Response response = await http.get(Uri.parse(baseUrl));
if (response.statusCode == 200) {
List<String> items = [];
var jsonData = json.decode(response.body) as List;
for (var element in jsonData) {
items.add(element["ClassName"]);
}
return items;
} else {
throw response.statusCode;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("DropDown List"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FutureBuilder<List<String>>(
future: getAllCategory(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var data = snapshot.data!;
return DropdownButton(
// Initial Value
value: dropdownvalue ?? data[0],
// Down Arrow Icon
icon: const Icon(Icons.keyboard_arrow_down),
// Array list of items
items: data.map((String items) {
return DropdownMenuItem(
value: items,
child: Text(items),
);
}).toList(),
// After selecting the desired option,it will
// change button value to selected value
onChanged: (String? newValue) {
setState(() {
dropdownvalue = newValue!;
});
},
);
} else {
return const CircularProgressIndicator();
}
},
),
],
),
),
);
}
}
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
I have a list of arrays i need to pass it to the other stateful widget and show the array there
This is my function code which retrieve data from API
Future<List> doSomeAsyncStuff() async {
final storage = new FlutterSecureStorage();
String value = await storage.read(key: 'Cnic');
print(value);
String url = 'http://api.php?offset=0&limit=1&cnic=${value}' ;
final msg = jsonEncode({"cnic": value});
Map<String,String> headers = {'Content-Type':'application/json'};
String token = value;
final response = await http.get(url);
var Data = json.decode(response.body);
print(Data);
var familyMembers = Data["records"][0]["family_members"];
print(familyMembers);
for (var familyMember in familyMembers){ //prints the name of each family member
print(familyMember["name"]);
print(familyMember["gender"]);
}
}
As you can see there is 2 list familyMember["name"] and familyMember["gender"] i need to pass it to statefulwidget
I am simple passing it like this
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PersonalPage(familyMember["name"], familyMember["gender"])),
);
This is my other stateful widget I need to show the array of name and gender here
import 'package:flutter/material.dart';
class PersonalPage extends StatefulWidget {
final String name;
final String gender;
PersonalPage(this.name, this.gender);
#override
_PersonalPageState createState() => _PersonalPageState();
}
class _PersonalPageState extends State<PersonalPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('I need to print name and gender here ')
),
);
}
}
flut
Try this and change your code as per this: As your First Page code is missing I have created a dummy forst Page.
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
title: 'My APP',
home: FirstRoute(),
));
}
class FirstRoute extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('List of ....'),
),
body: Center(
child: RaisedButton(
child: Text('Open details'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PersonalPage("NAME","GENDER")),
);
},
),
),
);
}
}
class PersonalPage extends StatefulWidget {
final String name;
final String gender;
PersonalPage(this.name, this.gender);
#override
_PersonalPageState createState() => _PersonalPageState();
}
class _PersonalPageState extends State<PersonalPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
children : [
Text(widget.name),
Text(widget.gender),
]
)
),
);
}
}
You are doing wrong you are passing list and in stateful widget you mention its a string you can do something like this
List<String> familyMemberName = [];
List<String> familyMemberGender = [];
Future<List> doSomeAsyncStuff() async {
final storage = new FlutterSecureStorage();
String value = await storage.read(key: 'Cnic');
print(value);
String url = 'http://api.php' ;
final msg = jsonEncode({"cnic": value});
Map<String,String> headers = {'Content-Type':'application/json'};
String token = value;
final response = await http.get(url);
var Data = json.decode(response.body);
print(Data);
var familyMembers = Data["records"][0]["family_members"];
print(familyMembers);
for (var familyMember in familyMembers){
familyMemberName.add(familyMember["name"]);
familyMemberGender.add(familyMember["gender"]);
print(familyMemberName);
}
}
and in you personal widget like this
import "package:flutter/material.dart";
class PersonalPage extends StatefulWidget {
final List<String> names;
final List<String> relation;
PersonalPage(this.names,this.relation);
#override
_PersonalPageState createState() => _PersonalPageState();
}
class _PersonalPageState extends State<PersonalPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body:
ListView.builder( //use ListView here to show all the names and genders
itemCount: widget.names.length,
itemBuilder: (BuildContext context,int index){
return Padding(
padding: EdgeInsets.only(left: 10, right: 10, bottom: 10, top: 10),
child: Card(
child: Padding(
padding: EdgeInsets.all(5),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text('Name:', style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),),
Text(widget.names[index])
],
),
Row(
children: <Widget>[
Text('Gender:', style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),),
Text(widget.genders[index])
],
),
],
),
),
),
);
})
);
}
}
Sorry i test code so thats why i add it in card
Text(widget.name)
Text(widget.gender)
or
Text("My name is ${widget.name} and my gender is ${widget.gender}")
In the following class I have created a ListView of Strings which are stored sing shared preferences. Now I need to access the content of List<String> categoryList in another class. I do not know where to implement a get function to give other classes access to this List.
One Idea was to create a class for the List (But I dont want to mess up everything)
That is my Class with the List View
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Categories extends StatefulWidget {
#override
_CategoriesState createState() => _CategoriesState();
}
class _CategoriesState extends State<Categories> {
List<String> categoryList = List<String>();
TextEditingController _textFieldController = TextEditingController();
#override
Widget build(BuildContext context) {
_update();
return Scaffold(
appBar: AppBar(
title: Text("Categories"),
),
body: SafeArea(
child: Container(
color: Colors.white,
child: getCategoriesListView(),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
_displayDialog(context);
});
},
),
);
}
ListView getCategoriesListView() {
return ListView.builder(
itemCount: categoryList.length,
itemBuilder: (context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
title: Text(categoryList[position]),
trailing: GestureDetector(
child: Icon(
Icons.delete,
color: Colors.grey,
),
onTap: () {
setState(() {
_delete(context, categoryList[position]);
});
},
),
),
);
});
}
void _add(BuildContext context, String category) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
categoryList.add(category);
prefs.setStringList('Categories', categoryList);
}
void _delete(BuildContext context, String category) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
categoryList.remove(category);
prefs.setStringList('Categories', categoryList);
}
void _update() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
setState(() {
categoryList = prefs.getStringList('Categories');
});
}
void showSnackBar(BuildContext context, String message) async {
final snackBar = SnackBar(content: Text(message));
Scaffold.of(context).showSnackBar((snackBar));
}
_displayDialog(BuildContext context) async {
_textFieldController.clear();
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add new category'),
content: TextField(
controller: _textFieldController,
),
actions: <Widget>[
FlatButton(
child: Text('ADD'),
onPressed: () {
setState(() {
String name = _textFieldController.text;
_add(context, name);
Navigator.of(context).pop();
});
},
),
FlatButton(
child: Text('CANCEL'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
}
}
Second Class
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class MonthlyOverview extends StatefulWidget {
#override
_MonthlyOverviewState createState() => _MonthlyOverviewState();
}
class _MonthlyOverviewState extends State<MonthlyOverview> {
List<String> _categories = new List<String>();
#override
Widget build(BuildContext context) {
_getCategory().then((value) {
_categories = value;
});
print(_categories);
return Scaffold(
appBar: AppBar(),
body: Container(
color: Colors.white,
),
);
}
_getCategory() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> categoryList = prefs.getStringList('Categories');
return categoryList;
}
}
Console output
I/flutter (13417): []
#Frederik, have you tried implementing a get function in your second class and accessing the list? It could be something like this in your second class,
_getCategory() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> categoryList = prefs.getStringList('Categories');
return categoryList;
}
Call (depends on where you're calling it but this should give you an idea):
List<String> _categories = new List<String>();
_getCategory().then((value) {
_categories = value;
});
//Your _categories has the value now , use it here.
Full code:
void main() {
runApp(MaterialApp(
home: new MyApp(),
routes: <String, WidgetBuilder>{
"/monthlyOverview" : (BuildContext context)=> new MonthlyOverview(),
//add more routes here
}
));
}
class MyApp extends StatefulWidget {
#override
MyAppState createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: Padding(
padding: EdgeInsets.all(20.0),
child: Center(
child: FlatButton(
child: Text('Next', style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold),),
onPressed: () async {
List<String> categoryList = ['Item 1', 'Item 2', 'Item 3'];
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setStringList('Categories', categoryList);
Navigator.of(context).pushNamed("/monthlyOverview");
},
)
)
),
);
}
}
class MonthlyOverview extends StatefulWidget {
#override
_MonthlyOverviewState createState() => _MonthlyOverviewState();
}
class _MonthlyOverviewState extends State<MonthlyOverview> {
List<String> _categories = new List<String>();
#override
void initState() {
super.initState();
_getCategory().then((value) {
_categories = value;
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
color: Colors.white,
child: _categories.length > 0 ? Text(_categories[0] + '\n' + _categories[1] + '\n' + _categories[2], style: TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold),) : Text(''),
)
),
);
}
_getCategory() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> categoryList = prefs.getStringList('Categories');
return categoryList;
}
}
Hope this helps.
I tried to do a dropdown menu like this:
I found this exemple in stackoverflow to add image in dropdown but currently it's a list and I don't know how add different images
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
#override
_TestState createState() => new _TestState();
}
class _TestState extends State<Test> {
var _img = new
Image.network("https://upload.wikimedia.org/wikipedia/commons/thumb/8/89/TUCPamplona10.svg/500px-TUCPamplona10.svg.png");
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text("Test Drop"),),
body: new Center(
child: new Container (
height: 50.0,
child:new DropdownButton(
items: new List.generate(10, (int index){
return new DropdownMenuItem(child: new Container(
padding: const EdgeInsets.only(bottom: 5.0),
height: 100.0,
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_img,
new Text("Under 10")
],
),
));
})
, onChanged: null),),
),
);
}
}
I did it with JSON. you can call multiple values inside dropdown.
import "package:flutter/material.dart";
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
class TestApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<TestApp> {
String _mySelection;
final String url = "http://webmyls.com/php/getdata.php";
List data = List(); //edited line
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(resBody);
return "Sucess";
}
#override
void initState() {
super.initState();
this.getSWData();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Hospital Management"),
),
body: new Center(
child: new DropdownButton(
items: data.map((item) {
return new DropdownMenuItem(
child: Row(
children: <Widget>[
Text(item['item_name']),
],
),
value: item['id'].toString(),
);
}).toList(),
onChanged: (newVal) {
setState(() {
_mySelection = newVal;
});
},
value: _mySelection,
),
),
);
}
}
modify this,
children: <Widget>[
Text(item['item_name']),
Text(item['item_name']),
Text(item['item_name']),
],