how to use Json list in dropdown button in flutter - json

I have this code which works and print the list but when i use it in a dropdown button, it throws the null red screen error while running the app.
Future<void> readJson() async {
final response = await rootBundle.loadString('assets/json/units.json');
final data = await json.decode(response);
setState(() {
List jsonList = data["length"] as List;
print(jsonList);
});
}
here is how the Json file structure looks like
{
"length" : [
{
"name": "Meter",
"conversion": 1.0,
"base_unit": true
},
{
"name": "Millimeter",
"conversion": 1000.0
},
{
"name": "Centimeter",
"conversion": 100.0
}
]
}
and here is how the dropdown button looks like,
Widget customJsonDropDown(String value, void onChange(val)) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(9),
color: Colors.white,
),
child: Padding(
padding: const EdgeInsets.only(left: 10, right: 5),
child: SizedBox(
//width: 80,
height: 50,
child: DropdownButton<String>(
value: value,
onChanged: (val) {
onChange(val);
},
items: jsonList?.map((item) {
return DropdownMenuItem(
child: Text(item['name']),
value: item['conversion'].toString(),
);
}).toList() ??
[],
underline: Container(),
isExpanded: true,
))));
}
any help is highly appreciated.

What are you sending in as the value parameter to customJsonDropDown?
The error message is saying either none of the value properties of any of the items you have passed to the DropdownButton match the value set the DropdownButton itself, or that more than one do. Can you confirm what item['conversion'].toString() evaluates to, and if exactly one of those values matches the DropdownButton's value?
EDIT:
Let me try to clarify a bit:
Widget customJsonDropDown(String value, void onChange(val)) {
return ...
child: DropdownButton<String>(
value: value, // <-- this needs exactly one corresponding DropdownMenuItem, or be null
onChanged: (val) {
onChange(val); // <-- this needs to update the value above to a value that also matches exactly one of the items you set below, or null
},
items: jsonList?.map((item) {
return DropdownMenuItem(
child: Text(item['name']),
value: item['conversion'].toString(), // <-- exactly one of these has to match the DropdownButton's value above, if not null
);
}).toList() ??
[],
// ...

Related

Fetching Json from api error Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<dynamic>'

Hello i have one question i was fetching categories from api which works fine in postman but on flutter i didn't use model class just using dio i need to fetch this json api as an array for top bar vertical scroll of categories.
here is my postman response
{
"data": [
{
"id": 1,
"name": "Electronics",
"color": "#ff8000"
},
{
"id": 2,
"name": "SpareParts",
"color": "#00ff40"
},
]
}
and in flutter i used
getCatagories() async {
var tokens;
var dioo = Dio();
dioo.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
var customHeaders = {
'content-type': 'application/json',
};
options.headers.addAll(customHeaders);
return options;
}));
var response = await dioo.get("https://www.mywebiste.com/api/cat");
if(response.data.isEmpty||response.data==null)
{
}
else
{
}
return response.data;
}
to fetch these catagories
i have used
List categories = [];
#override
void initState() {
getCatagories().then((data) {
setState(() {
categories = data;
});
});
super.initState();
}
// by default first item will be selected
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.symmetric(vertical: kDefaultPadding / 2),
height: 30,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: categories.length,
itemBuilder: (context, index) => GestureDetector(
onTap: () {
Fluttertoast.showToast(
msg: "This is Center Short Toast"+selectedIndex.toString(),
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0
);
setState(() {
selectedIndex = index;
});
},
child: Container(
alignment: Alignment.center,
margin: EdgeInsets.only(
left: kDefaultPadding,
// At end item it add extra 20 right padding
right: index == categories.length - 1 ? kDefaultPadding : 0,
),
padding: EdgeInsets.symmetric(horizontal: kDefaultPadding),
decoration: BoxDecoration(
color: index == selectedIndex
? Colors.white.withOpacity(0.4)
: Colors.transparent,
borderRadius: BorderRadius.circular(6),
),
child: Text(
categories[index],
style: TextStyle(color: Colors.white),
),
),
),
),
);
}
so when i run these app categories will not appear for scrollbar and error is Unhandled Exception: InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List
You are getting the data from request as Map and assigning it to List.
you should make categories as Map:
Map categories;
Note: don't give it generics.
after that you will have some problems in the code below while looping in the categories.
That's another question. :)

Flutter how to search an object in complex json

My application is a simple calculator but I am a little lost in flutter...
I have a text field entered by the user which is a distance.
Depending on this distance, I need to look in my local values ​​of the application stored in a json for the closest value and retrieve the index.
Here is my json:
{
"charges" : [
{
"type" : 1,
"distance": 800,
"setting": 1122,
"bond" : 44,
"index" : 1
},
{
"type" : 1,
"distance": 850,
"setting": 1076,
"bond" : 50,
"index" : 2
},
{
"type" : 2,
"distance": 800,
"setting": 1336,
"bond" : 37,
"index" : 3
},
{
"type" : 2,
"distance": 900,
"setting": 1299,
"bond" : 39,
"index" : 4
}
]
}
If the user enters 836m for example, I have to compare the different ammunition (type 1 and 2) and look at the distance closest to the bottom.
Here the closest distance to the bottom is 800 for ammunition 1 and 2.
{
"type" : 1,
"distance": 800,
"setting": 1122,
"bond" : 44,
"index" : 1
},
{
"type" : 2,
"distance": 800,
"setting": 1336,
"bond" : 37,
"index" : 3
}
But I have to find only one charge at the end which corresponds to my need.
For that I have to look at the setting which must be closest to 1100 at the superior.
The setting of the charge 1 is the closest so I need to keep the index 1.
How to do that ? Is it the good method to use json file ? The structure of my json file is good fot do that ?
This is my Homepage.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:convert';
import 'dart:async';
class HomeController extends StatefulWidget {
HomeController({Key key, this.title}) : super(key: key);
final String title;
#override
_HomeControllerState createState() => _HomeControllerState();
}
class _HomeControllerState extends State<HomeController> {
String _distance;
final _formKey = GlobalKey<FormState>();
// Widget ************************************
Widget _buildDistance() {
return TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Distance',
hintText: "Enter a distance",
),
keyboardType: TextInputType.number,
validator: (String value){
int distance = int.tryParse(value);
if(distance == null){
return "Distance is needed";
}
if(distance <= 0){
return "Distance must be greater than zero";
}
},
onSaved: (String value){
_distance = value;
},
);
}
// End Widget ************************************
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (() => FocusScope.of(context).requestFocus(FocusNode())),
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: FutureBuilder(
future : DefaultAssetBundle.of(context).loadString('assets/jsons/charge.json'),
builder : (context, snapshot){
var myjson = json.decode(snapshot.data.toString());
return Container(
margin: EdgeInsets.all(24),
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_buildDistance(),
SizedBox(height: 100),
RaisedButton(
child: Text(
'Calculer',
style: TextStyle(color:Colors.blue, fontSize : 16),
),
onPressed: (){
if(!_formKey.currentState.validate()){
return;
}
_formKey.currentState.save();
print(_distance);
Map<String, dynamic> data = {
"distance" : _distance,
};
print('result : ${data['distance']}');
print(myjson);
},
),
],
),
),
);
},
),
),
);
}
}
You need to parse the JSON. I would personally parse it whenever the application starts and keep it in memory (unless this JSON is really long!!). For instance, you can store the information in an array in which each element is an object of class Charge that is a simple POJO class that stores the information needed for a charge (type, distance...).
Then when you're searching for the selected Charge, you can simply traverse the array and keep track of which charge has the closest distance to the user-specified
var minDistance = double.maxFinite;
var correctCharge = null;
for(var charge in charges){
double curDistance = abs(charge.distance - userSpecifiedDIstance);
if(curDistance < minDistance){
minDistance = curDistance;
correctCharge = charge;
}
}
If you want to optimise this so you don't traverse the whole array every time, you can use search methods like binary search (if you don't have a lot of charges, you don't need to optimize.)

How can i add multiple expand tile with checkbox list tile using Json in flutter

this json has two data first only name and second is inside there also name which is service name. ex 'Travel and Stay' and 'Religious' is main name which has to be displayed in expansion tile name and The 'Church/ Baptism' and 'Hindu Temples' is a subitem which is displayed inside checkbox list tile. Hope you understand :slightly_smiling_face: Please Help me
class _MyHomePageState extends State<MyHomePage> {
var lovCountryServices = [
{
"services": [
{
"service_group_id": 22,
"service_category": "B",
"name": "Air Tickets",
"id": 228
},
{
"service_group_id": 22,
"service_category": "W",
"name": "Boys Hostel",
"id": 229
},
],
"name": "Travel and Stay",
"is_active": true,
"id": 22
},
{
"services": [
{
"service_group_id": 19,
"service_category": "B",
"name": "Church/ Baptism",
"id": 193
},
{
"service_group_id": 19,
"service_category": "B",
"name": "Hindu Temples",
"id": 194
}
],
"name": "Religious",
"is_active": true,
"id": 19
}
];
List<_Result> _results = [];
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
children: <Widget>[
ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(8.0),
itemCount: lovCountryServices.length,
itemBuilder: (BuildContext context, int index) {
var item = lovCountryServices[index];
var items= lovCountryServices[index]['services'];
return ExpansionTile(
title: Text(item['name']),
children: <Widget>[
CheckboxListTile(
title: Text("temp"),
value: item['is_active'],
onChanged: (val) {
setState(() {
item['is_active'] = val;
});
},
),
],
);
},
),
RaisedButton(
onPressed: () => print("sending to backend"),
child: Text("SEND"),
)
],
)),
);
}
}
I want thw data in checkbox list tile right there is dummy data called TEMP and i want the data from json right now in json there is 'Boys Hostel' this data needs to comes inside the checkbox listtile. Hope you undestand please help me
Working Code: You can use a Map variable to store boolean value.
Map<String, bool> _selection = {};
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Dummy'),
),
body: Center(
child: Column(
children: <Widget>[
ListView.builder(
shrinkWrap: true,
padding: const EdgeInsets.all(8.0),
itemCount: lovCountryServices.length,
itemBuilder: (BuildContext context, int index) {
var item =
lovCountryServices[index]; // should be outside build function
List items = item['services']; // should be outside build function
return ExpansionTile(
title: Text(item['name']),
children: List.generate(items.length, (i) {
_selection[items[i]['name']] =
_selection[items[i]['name']] ?? item['is_active'];
return CheckboxListTile(
title: Text(items[i]['name']),
value: _selection[items[i]['name']],
onChanged: (val) {
setState(() {
_selection[items[i]['name']] = val;
});
},
);
}),
);
},
),
RaisedButton(
onPressed: () => print("sending to backend"),
child: Text("SEND"),
)
],
)),
);
}

How to test if json property is present during the build of a Flutter ListView

I'm beginner in Flutter and Dart.
I have a local JSON file, read it and I want to display the JSON Data in the ListView.
But in my JSON data I haven't always all the different properties.
So when I want to display a text, the value of the property is no existing because the property is not existing (In the case is the Property "description".
How could I solve it ?
Thank you in advance for your help
I tried ternary operator
I tried with the function containsKey
But maybe I did it wong ?
... json
[
{
"createdBy": "bddae0de-320c-41a9-a69b-75793758b7a7",
"description": "Fhjifgsdsdsd",
"endDateTime": "1477490400000",
"hasPicture": "false",
"isActive": "true",
"isAdminActive": "true",
"maxParticipants": "50",
"startDateTime": "1476799200000",
"title": "Song Church Story Telling",
"type": "Music"
},
{
"createdBy": "-KHzgxS6KBqu1rNmJzpT",
"endDateTime": "1476378000000",
"hasPicture": "false",
"isActive": "true",
"isAdminActive": "true",
"startDateTime":"1476205200000",
"title": "Test greg T",
"titleDate": "Tuesday, 11 Oct 8:00 PM",
"type": "Games"
}
]
...
... flutter
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Load local JSON file"),
),
body: new Container(
child: new Center(
// Use future builder and DefaultAssetBundle to load the local JSON file
child: new FutureBuilder(
future: DefaultAssetBundle.of(context)
.loadString('assets/data/ckevents_data.json'),
builder: (context, snapshot) {
// Decode the JSON
var newData = json.decode(snapshot.data.toString());
return new ListView.builder(
// Build the ListView
itemBuilder: (BuildContext context, int index) {
return new Card(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
new Text("Title: " + newData[index]['title'],
style: new TextStyle(
fontSize: 20.0, color: Colors.blue)),
new Text(
"Description: " +
((newData[index].containsKey('description')) ? ('') : (newData[index]['description'])),
style: new TextStyle(
fontSize: 10.0, color: Colors.pink)),
new Text("Categorie: " + newData[index]['type'],
style: new TextStyle(
fontSize: 15.0, color: Colors.red)),
new Text(
"Date: " +
DateTime.fromMillisecondsSinceEpoch(
newData[index]['startDateTime'])
.add(Duration(days: 700))
.toString(),
style: new TextStyle(
fontSize: 10.0, color: Colors.black))
],
),
);
},
itemCount: newData == null ? 0 : newData.length,
);
}),
),
));
}
}
...
You can use the null coalesce operator like so:
new Text("Description: " + newData[index]['description'] ?? ''),
This will print the description if it exists, and an empty string if it doesn't.
Try this way
1. make model class for your response json like this way..
class UserData {
final int albumId;
final int id;
final String title;
final String url;
final String thumbnailUrl;
UserData({this.albumId, this.id, this.title, this.url, this.thumbnailUrl});
factory UserData.fromJson(Map<String, dynamic> json) {
return new UserData(
albumId: json['albumId'],
id: json['id'],
title: json['title'],
url: json['url'],
thumbnailUrl: json['thumbnailUrl']);
}
}
now make list object ..
List<UserData> list = List();
then add data..
list = (json.decode(response.body) as List)
.map((data) => UserData.fromJson(data))
.toList();
read json file like this way..
class _ApiCallScreenState extends State<ApiCallScreen> {
#override
void initState() {
String data = await DefaultAssetBundle.of(context).loadString("assets/data.json");
list = (json.decode(data) as List)
.map((data) => UserData.fromJson(data))
.toList();
super.initState();
}

Flutter JSON Nested to Lisview Builder

sorry i have searched on youtube and google but i'm still not getting any clue to parse JSON nested to listview builder.
my json result
[
{
"ID_Type": "1",
"Type": "Food",
"Item": [
{
"SLU_Number": "3",
"SLU_Name": "Food"
}
]
},
{
"ID_Type": "2",
"Type": "Beverages",
"Item": [
{
"SLU_Number": "1",
"SLU_Name": "Non Alcohol"
},
{
"SLU_Number": "2",
"SLU_Name": "Alchohol"
}
]
}
]
i want ID_Type, Type,Item (SLU_Number and SLU Name) throw all value to Listview.builder
thank you.
my code on flutter, i follow some code on youtube and that throw the value to List but i don't how to throw the value to Listview.builder
class Products {
final ID_Type;
final Name_Type;
final Items;
Products({
this.ID_Type,
this.Name_Type,
this.Items,
});
factory Products.fromJson(Map<String, dynamic> json) {
return Products(
ID_Type: json["ID_Type"],
Name_Type: json["Type"],
Items: Item.fromJson(json["Item"]),
);
}
}
class Item {
final SLU_Number;
final SLU_Name;
Item({
this.SLU_Number,
this.SLU_Name,
});
factory Item.fromJson(Map<String, dynamic> json) {
return Item(
SLU_Number: json["SLU_Number"],
SLU_Name: json["SLU_Name"],
);
}
}
here below is my Future to throw all the "json" result to List
//------------------------------Start Syntax for List SLU
final listslu = new List<ListSLU>();
final GlobalKey<RefreshIndicatorState> _refreshlistslu =
GlobalKey<RefreshIndicatorState>();
Future<void> ListSLUs() async {
listslu.clear();
setState(() {
loading = true;
});
try {
final response = await http.get(BaseUrl.ListSLU);
if (response.contentLength == 2) {
} else {
final data = jsonDecode(response.body);
data.forEach((api) {
final b = new ListSLU(
api['ID_Type'].toString(),
api['SLU_Number'].toString(),
api['SLU_Name'].toString(),
);
listslu.add(b);
print(api['SLU_Name'].toString());
});
}
} catch (e) {
print("Error List SLU :");
print(e);
}
}
//------------------------------End Syntax for List Type
after parsing all json result and then all value from json i throw to body
Expanded(
flex: 2,
child: ListView.builder(
itemCount: listslu.length,
itemBuilder: (context,i){
final z = listslu[i];
return GestureDetector(
onTap: (){
},
child: Container(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Row(
children: <Widget>[
Text(z.SLU_Number +' - '+ z.SLU_Name),
],
),
],
)
],
),
),
);
}
)
),