Related
I'm trying to populate a ReorderableSliverList with data from an API using FutureBuilder.
Model (RouteOrderTable)
RouteOrderTable(
{required this.deliveryPeriod,
required this.driverId,
required this.processId,
required this.routeId,
required this.routeLines,
required this.status,
required this.vanId});
RouteOrderTable.fromJson(Map<String, dynamic> json) {
deliveryPeriod = json['deliveryPeriod'];
driverId = json['driverId'];
processId = json['processId'];
routeId = json['routeId'];
if (json['routeLines'] != null) {
routeLines = <RouteOrderLine>[];
json['routeLines'].forEach((v) {
routeLines!.add(new RouteOrderLine.fromJson(v));
});
}
status = json['status'];
vanId = json['vanId'];
}
Model (RouteOrderLine)
RouteOrderLine(
{required this.city,
required this.custAccount,
required this.custName,
required this.invoiceId,
required this.deliveryDate,
required this.productType,
required this.routeId,
required this.salesId,
required this.volume,
required this.weight});
RouteOrderLine.fromJson(Map<String, dynamic> json) {
city = json['city'];
custAccount = json['custAccount'];
custName = json['custName'];
deliveryDate = DateTime.tryParse(json['deliveryDate']);
invoiceId = json['invoiceId'];
productType = json['productType'];
routeId = json['routeId'];
salesId = json['salesId'];
volume = json['volume'];
weight = json['weight'];
}
JSON Data
[
{
"deliveryPeriod": 1,
"driverId": "",
"processId": "PRO000475",
"routeId": "ROU001804",
"routeLines": [
{
"city": "Naxxar",
"custAccount": "CUST010917",
"custName": "",
"deliveryDate": "2021-07-06T12:00:00",
"invoiceId": "",
"productType": 0,
"routeId": "ROU001804",
"salesId": "SO002496",
"volume": 0.011113889,
"weight": 8.700435
}
],
"status": 10,
"vanId": "TFI 943"
},
{
"deliveryPeriod": 2,
"driverId": "",
"processId": "PRO000475",
"routeId": "ROU001805",
"routeLines": [
{
"city": "Birkirkara",
"custAccount": "CUST010916",
"custName": "",
"deliveryDate": "2021-07-06T12:00:00",
"invoiceId": "",
"productType": 0,
"routeId": "ROU001805",
"salesId": "SO002497",
"volume": 0.005556111,
"weight": 4.349565
}
],
"status": 30,
"vanId": "HBA 804"
}
]
Screen - One of the issues here is that I cannot use removeAt() and insert() for the onReorder() because they aren't defined for the type Future.
class _SliverScreenState extends State<SliverScreenState> {
late Future<List<RouteOrderTable>> futureRouteTable;
#override
void initState() {
super.initState();
futureRouteTable = fetchData();
}
#override
Widget build(BuildContext context) {
void _onReorder(int oldIndex, int newIndex) {
/* setState(() {
Widget row = futureRouteTable!.removeAt(oldIndex);
futureRouteTable.insert(newIndex, row);
});*/
}
ScrollController _scrollController =
PrimaryScrollController.of(context) ?? ScrollController();
final someOtherSliver = SliverToBoxAdapter();
return FutureBuilder<List<RouteOrderTable>>(
future: futureRouteTable,
builder: (context, snapshot) {
Widget routeOrderListSliver;
final List<RouteOrderTable>? posts = snapshot.data;
if (snapshot.hasData) {
routeOrderListSliver = CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverAppBar(
flexibleSpace: FlexibleSpaceBar(
title: Text('ROUTE NO'),
),
),
ReorderableSliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(
title: Text(posts![index].routeId.toString(),
style: TextStyle(fontSize: 20.0),),
),
childCount: posts!.length,
),
onReorder: _onReorder,
),
],
);
}else {
routeOrderListSliver = Center(child: SliverToBoxAdapter(child: CircularProgressIndicator(),));
}
return CustomScrollView(
slivers: <Widget>[
someOtherSliver,
routeOrderListSliver
],
);
},
);
}
}
FetchData
Future<List<RouteOrderTable>> fetchData() async {
final response =
await http.get(Uri.parse('https://10.0.2.2:7038/api/route/1?siteId=1'));
try {
if (response.statusCode == 200) {
List<RouteOrderTable> lstRouteOrderTable = [];
Iterable l = jsonDecode(response.body);
lstRouteOrderTable = List<RouteOrderTable>.from(l.map((model) => RouteOrderTable.fromJson(model)));
return lstRouteOrderTable;
} else {
throw Exception('Failed to load route');
}
} catch (e) {
print(e);
}
return new List<RouteOrderTable>.empty();
}
ListView.builder
ListView _buildRouteOrderTable(
BuildContext context, List<RouteOrderTable>? lstRouteTable) {
return ListView.builder(
itemCount: lstRouteTable == null ? 0 : lstRouteTable.length,
//padding: EdgeInsets.all(8),
itemBuilder: (context, index) {
return Card(
elevation: 4,
child: ListTile(
title: Text(
lstRouteTable == null ? "" : lstRouteTable[index].routeId.toString(),
style: TextStyle(fontWeight: FontWeight.bold),
),
subtitle: Text(
lstRouteTable == null ? "" : lstRouteTable[index].processId.toString()),
),
);
},
);
}
You can define the _onReorder function inside the FutureBuilder and then use the snapshot to create a variable of RouteOrderTable.
This will give you access to the removeAt & insert functions.
There are two ways of doing this.
final List<RouteOrderTable>? posts = snapshot.data;
if (snapshot.hasData) {
void _onReorder(int oldIndex, int newIndex){
//1. Define the function here and then pass it as a parameter.
}
routeOrderListSliver = CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverAppBar(
flexibleSpace: FlexibleSpaceBar(
title: Text('ROUTE NO'),
),
),
ReorderableSliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(
title: Text(posts![index].routeId.toString(),
style: TextStyle(fontSize: 20.0),),
),
childCount: posts!.length,
),
onReorder: (int oldIndex, int newIndex){
// OR
// 2. You can directly create the function here.
},
),
],
);
}
Both ways, you get access to the posts variable where you can do your operations.
My dropdown working as expected . but when I selected a item my app crashing with error
There should be exactly one item with [DropdownButton]'s value: Instance of 'Partner'.
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
First I declare my variable in class
class _MultipleTestBookingState extends State<MultipleTestBooking> {
Partner? _selectedLab;
Datum? _selectedTest;
....................
declare with Partner?_selectedLab; because my dropdown menu takes in a list of Partners
Then using this variable to show the selected value in my dropdown
Container(
child: FutureBuilder<List<Partner>>(
future: AllPathLab(),
builder:
(BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState !=ConnectionState.done) {
return CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text("Somthing went wrong");
}
if (snapshot.hasData) {
return DropdownButton<Partner>(
value: _selectedLab,
hint: Text("Select Lab"),
items: snapshot.data.map((Partner data) =>
DropdownMenuItem<Partner>(
child: Text("${data.partnerName}"),
value: data,
)
).toList().cast<DropdownMenuItem<Partner>>(),
onChanged: (value){
setState(() {
_selectedLab=value;
encLabId = value!.encPartnerId;
GetTestByLab();
});
}
);
}
return Text("Waiting for Internet Connection");
},
),
),
Full code with my JSON response
So from the data that you provided i have created the code below:
import 'package:date_time_picker/date_time_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/Patner.dart';
import 'package:flutter_app/dataModel.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
home: MyApp(),
));
}
class MyApp extends StatefulWidget {
const MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Partner _selectedLab;
Datum _selectedTest;
Future getAllPathLabResults;
Future getTestByLabResult;
String encLabId = '';
void initState() {
super.initState();
getAllPathLabResults = allPathLab();
getTestByLabResult = getTestByLab();
}
String _selectedDate = DateTime.now().toString();
Future<List<Partner>> allPathLab() async {
String jsonData = jsonstring;
final model = modelFromJson(jsonData);
print("This is the list length : ${model.partner.length}");
List<Partner> arrData = model.partner;
// this Future is for sample as you will be fetching the api data remove this one
Future.delayed(Duration(seconds: 3));
return arrData;
}
Future<List<Datum>> getTestByLab() async {
print("This is the Id :$encLabId");
_selectedTest = null;
var response = await http.post(
Uri.parse("http://medbo.digitalicon.in/api/medboapi/GetTestByLab"),
body: ({"EncId": encLabId}));
if (response.statusCode == 200) {
final dataModel = dataModelFromJson(response.body);
print(dataModel.data.length);
for (final item in dataModel.data) {
print("This is hte test name :${item.testName}");
}
List<Datum> arrData = dataModel.data;
return arrData;
}
return [];
}
#override
Widget build(BuildContext context) {
var screenWidth = MediaQuery.of(context).size.width;
var screenHeight = MediaQuery.of(context).size.height;
var blockSizeHorizontal = (screenWidth / 100);
var blockSizeVertical = (screenHeight / 100);
return Scaffold(
body: SafeArea(
child: Container(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
title: Text("Booking Information",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: blockSizeHorizontal * 5,
fontFamily: 'Poppins',
color: Theme.of(context).primaryColor,
)),
subtitle: Text("Preferred Visit Date"),
),
),
Container(
margin: EdgeInsets.only(left: 20),
padding: EdgeInsets.only(left: 0, right: 150),
decoration: BoxDecoration(
color: Colors.lightBlue[50],
borderRadius: BorderRadius.all(Radius.circular(12)),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: DateTimePicker(
initialValue: DateTime.now().toString(),
//initialValue:'', // initialValue or controller.text can be null, empty or a DateTime string otherwise it will throw an error.
type: DateTimePickerType.date,
dateLabelText: 'Select Date',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: blockSizeHorizontal * 3.5,
fontFamily: 'Poppins',
color: Colors.green,
letterSpacing: 2.0,
),
firstDate: DateTime.now(),
lastDate: DateTime.now().add(Duration(days: 30)),
// This will add one year from current date
validator: (value) {
return null;
},
onChanged: (value) {
if (value.isNotEmpty) {
setState(() {
_selectedDate = value;
});
}
},
onSaved: (value) {
if (value.isNotEmpty) {
_selectedDate = value;
}
},
),
),
),
ListTile(
title: Text(
"Select Pathological Lab",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: blockSizeHorizontal * 4.0,
fontFamily: 'Poppins',
color: Theme.of(context).primaryColor,
),
),
),
Container(
child: FutureBuilder<List<Partner>>(
future: getAllPathLabResults,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text("Somthing went wrong");
}
if (snapshot.hasData) {
List<Partner> data =
snapshot.hasData ? snapshot.data : [];
return DropdownButton<Partner>(
value: _selectedLab,
hint: Text("Select Lab"),
//underline: SizedBox(),
//isExpanded: true,
items: data
.map((Partner data) => DropdownMenuItem<Partner>(
child: Text("${data.partnerName}"),
value: data,
))
.toList()
.cast<DropdownMenuItem<Partner>>(),
onChanged: (value) {
setState(() {
_selectedLab = value;
encLabId = value.encPartnerId;
getTestByLabResult = getTestByLab();
});
//GetTestByLab(value!.encPartnerId); // passing encid to my next API function
// GetTestByLab();
},
);
}
return Text("Waiting for Internet Connection");
},
),
),
//=========================================================== Dependent drop down===================================
ListTile(
title: Text(
"Test Name",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: blockSizeHorizontal * 4.0,
fontFamily: 'Poppins',
color: Theme.of(context).primaryColor,
),
),
),
Container(
child: FutureBuilder<List<Datum>>(
future: getTestByLabResult,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text("Select a Lab for your Test");
}
if (snapshot.hasData) {
List<Datum> data = snapshot.hasData ? snapshot.data : [];
return DropdownButton<Datum>(
value: _selectedTest,
hint: Text(""),
//underline: SizedBox(),
//isExpanded: true,
items: data
.map((Datum data) => DropdownMenuItem<Datum>(
child: Text("${data.testName}"),
value: data,
))
.toList()
.cast<DropdownMenuItem<Datum>>(),
onChanged: (value) {
print("This is the value : ${value.testName}");
setState(() {
_selectedTest = value;
});
//GetTestByLab(value!.encPartnerId); // passing encid to my next API function
});
}
return Text("Waiting for Internet Connection");
},
),
),
],
),
),
),
);
}
}
// used this as a sample
String jsonstring = '''{
"Status": "1",
"Message": "",
"Partner": [
{
"EncPartnerId": "IujyQXg8KZg8asLvK/FS7g==",
"PartnerName": "dasfdsf"
},
{
"EncPartnerId": "pEl2B9kuumKRxIxLJO76eQ==",
"PartnerName": "partner172"
},
{
"EncPartnerId": "eYwtNBXR6P/JDtsIwr+Bvw==",
"PartnerName": "nnkb"
},
{
"EncPartnerId": "kFgorcFF0G6RQD4W+LwWnQ==",
"PartnerName": "nnkjj"
},
{
"EncPartnerId": "U4exk+vfMGrn7cjNUa/PBw==",
"PartnerName": "mahadev"
},
{
"EncPartnerId": "tqkaSjTFgDf0612mp9mbsQ==",
"PartnerName": null
},
{
"EncPartnerId": "0aruO0FbYOu5IerRBxdT8w==",
"PartnerName": "Suraksha Diagnostics"
},
{
"EncPartnerId": "65gtodyhbtdInTsJWr1ZkA==",
"PartnerName": "Rasomoy pvt. Hospital"
},
{
"EncPartnerId": "LEuT1eIlpLEMAAkZme3wpQ==",
"PartnerName": "Tangra medical House"
},
{
"EncPartnerId": "q8O8YMzYKXSB4RtkX4k7Lw==",
"PartnerName": "Partner new"
}
]
}''';
Models for the apis:
// To parse this JSON data, do
//
// final model = modelFromJson(jsonString);
import 'dart:convert';
Model modelFromJson(String str) => Model.fromJson(json.decode(str));
String modelToJson(Model data) => json.encode(data.toJson());
class Model {
Model({
this.status,
this.message,
this.partner,
});
String status;
String message;
List<Partner> partner;
factory Model.fromJson(Map<String, dynamic> json) => Model(
status: json["Status"],
message: json["Message"],
partner:
List<Partner>.from(json["Partner"].map((x) => Partner.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Status": status,
"Message": message,
"Partner": List<dynamic>.from(partner.map((x) => x.toJson())),
};
}
class Partner {
Partner({
this.encPartnerId,
this.partnerName,
});
String encPartnerId;
String partnerName;
factory Partner.fromJson(Map<String, dynamic> json) => Partner(
encPartnerId: json["EncPartnerId"],
partnerName: json["PartnerName"] == null ? null : json["PartnerName"],
);
Map<String, dynamic> toJson() => {
"EncPartnerId": encPartnerId,
"PartnerName": partnerName == null ? null : partnerName,
};
}
second api parsing model
// To parse this JSON data, do
//
// final dataModel = dataModelFromJson(jsonString);
import 'dart:convert';
DataModel dataModelFromJson(String str) => DataModel.fromJson(json.decode(str));
String dataModelToJson(DataModel data) => json.encode(data.toJson());
class DataModel {
DataModel({
this.status,
this.message,
this.data,
});
String status;
String message;
List<Datum> data;
factory DataModel.fromJson(Map<String, dynamic> json) => DataModel(
status: json["Status"],
message: json["Message"],
data: json["Data"] == null
? []
: List<Datum>.from(json["Data"].map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Status": status,
"Message": message,
"Data":
data == null ? [] : List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Datum {
Datum({
this.testId,
this.encTestId,
this.testName,
this.noOfPartner,
this.testFee,
this.discountedFee,
this.bookingFee,
this.reportTime,
this.note,
this.createBy,
this.createDate,
this.modBy,
this.modDate,
this.activeStatus,
this.permission,
});
String testId;
dynamic encTestId;
String testName;
dynamic noOfPartner;
dynamic testFee;
dynamic discountedFee;
dynamic bookingFee;
dynamic reportTime;
dynamic note;
dynamic createBy;
dynamic createDate;
dynamic modBy;
dynamic modDate;
dynamic activeStatus;
dynamic permission;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
testId: json["TestId"],
encTestId: json["EncTestId"],
testName: json["TestName"],
noOfPartner: json["NoOfPartner"],
testFee: json["TestFee"],
discountedFee: json["DiscountedFee"],
bookingFee: json["BookingFee"],
reportTime: json["ReportTime"],
note: json["Note"],
createBy: json["CreateBy"],
createDate: json["CreateDate"],
modBy: json["ModBy"],
modDate: json["ModDate"],
activeStatus: json["ActiveStatus"],
permission: json["Permission"],
);
Map<String, dynamic> toJson() => {
"TestId": testId,
"EncTestId": encTestId,
"TestName": testName,
"NoOfPartner": noOfPartner,
"TestFee": testFee,
"DiscountedFee": discountedFee,
"BookingFee": bookingFee,
"ReportTime": reportTime,
"Note": note,
"CreateBy": createBy,
"CreateDate": createDate,
"ModBy": modBy,
"ModDate": modDate,
"ActiveStatus": activeStatus,
"Permission": permission,
};
}
So when you initially fetch the data based on the id and select the second dropdown. now when you change the lab you have the make the selected text to null.
and you are are also using the futurebuilder method in wrong manner as there is setstate getting called it is creating multiple rebuids and giving error.
please run the code and check if its working.
My JSON looks like this:
{
Info: [
{
c_type_id: "1",
cleaning type: "A Cleaning"
},
{
c_type_id: "2",
cleaning type: "B Cleaning"
},
{
c_type_id: "3",
cleaning type: "C Cleaning"
},
{
c_type_id: "4",
cleaning type: "D Cleaning"
},
{
c_type_id: "5",
cleaning type: "E Cleaning"
},
]
}
and here is the code:
The following code is created by this
Class 1:
class Album {
List<Info> info;
Album({this.info})
Album.fromJson(Map<String, dynamic> json) {
if (json['Info'] != null) {
info = List<Info>.empty();
json['Info'].forEach((v) {
info.add(new Info.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.info != null) {
data['Info'] = this.info.map((v) => v.toJson()).toList();
}
return data;
}
}
class 2:
class Info {
String cTypeId;
String cleaningType;
Info({this.cTypeId, this.cleaningType});
Info.fromJson(Map<String, dynamic> json) {
cTypeId = json['c_type_id'];
cleaningType = json['cleaning type'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['c_type_id'] = this.cTypeId;
data['cleaning type'] = this.cleaningType;
return data;
}
}
This is the error I get when I execute the code:
error: The argument type 'List' can't be assigned to the parameter type 'String'.
Hoping for help!
You should Try below code your problem has been solved ->
Declare your API Call funtion
Future<List<dynamic>> getInfoData() async {
String url = 'https://fillmmaka.com/gigocleanapi/cleanintypes.php';
var response = await http.get(Uri.parse(url), headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
});
return json.decode(response.body)['Info'];
}
Declare your Widget
Center(
child: FutureBuilder<List<dynamic>>(
future: getInfoData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
var id = snapshot.data[index]['c_type_id'];
var type = snapshot.data[index]['cleaning type'];
return Card(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.green.shade300,
),
borderRadius: BorderRadius.circular(15.0),
),
child: ListTile(
leading: Text(id),
title: Text(type),
),
);
},
),
);
}
return CircularProgressIndicator();
},
),
),
Your Screen look like this ->
What is your goal? What do you want to show on the screen?
For example, do you want to show a list with all the cleaning types?
You are getting this error because the attribute info in your Album class is a List:
class Album {
List<Info> info;
If you want to show the cleaningType of the first info on the list, you may do something like this:
return Text(snapshot.data.info[0].cleaningType);
Just keep in mind this will crash if the info list is empty.
you are trying to access the whole list there just use snapshot.data.info[index].variableName you want to access
and you will be good to go
I got json object from API and i have to show this as a dropdown.
Json response
{
"deliveryCharges": {
"_id": "607b156404fb0a0184db98fe",
"businessId": "607b14ef04fb0a0184db98e3",
"createdAt": "2021-04-17T17:05:40.546Z",
"updatedAt": "2021-04-18T10:16:13.633Z",
"__v": 0,
"deliveryZones": {
"Bangladesh": { // country dropdown item 1
"Mirpur": {. // city dropdown item 1
"deliveryCost": "50",
"status": true
}
},
"American Samoa": { // country dropdown item 2
"lost city": { // city dropdown item 2
"deliveryCost": "50",
"status": true
}
}
}
}
}
Here Bangladesh and American Samoa in country drop down
Here Mirpur and lost city in city drop down
I thing i have to change json object to array. But did not found good example.
Advanced thanks
Since
"deliveryZones": {
"Bangladesh": { // country dropdown item 1
"Mirpur": {. // city dropdown item 1
"deliveryCost": "50",
"status": true
}
},
"American Samoa": { // country dropdown item 2
"lost city": { // city dropdown item 2
"deliveryCost": "50",
"status": true
}
}
}
this object will be stored in Map Data structure
you can convert map keys to list
map.keys.toList()
First, declare two variables of an array.
List<String> countryList = [];
List<String> zoneList = [];
After that parse JSON data which is provided from API response.
Map<String, dynamic> decoded = json.decode(response);
for (var colour in decoded.keys) {
List<String>.from(decoded[colour]['deliveryZones'].keys.map((model) {
countryList.add(model);
}));
List<String>.from(decoded[colour]['deliveryZones']['Bangladesh'].keys.map((model) {
zoneList.add(model);
}));
}
Now print and show the output
print("country $countryList");
print("zoneList $zoneList");
So I have Created a sample Example Based on the json that you provided.
json you provided :
{
"deliveryCharges": {
"_id": "607b156404fb0a0184db98fe",
"businessId": "607b14ef04fb0a0184db98e3",
"createdAt": "2021-04-17T17:05:40.546Z",
"updatedAt": "2021-04-18T10:16:13.633Z",
"__v": 0,
"deliveryZones": {
"Bangladesh": {
"Mirpur": {
"deliveryCost": "50",
"status": true
}
},
"American Samoa": {
"lost city": {
"deliveryCost": "50",
"status": true
}
}
}
}
}
Based on the json I have Made an Example :
import 'package:flutter/material.dart';
import 'dart:convert';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var _isLoading = false;
String countryValue;
List<String> countriesList = [];
List<String> cityList = [];
String cityValue;
#override
void initState() {
super.initState();
getData();
}
getData() async {
setState(() {
_isLoading = true;
});
String data =
await DefaultAssetBundle.of(context).loadString("json/parse.json");
var item = json.decode(data);
item.forEach((key, value) {
print(value["deliveryZones"]);
value["deliveryZones"].forEach((key, value) {
print(key);
countriesList.add(key);
value.forEach((key, value) {
print(key);
cityList.add(key);
});
});
});
setState(() {
_isLoading = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("Users List "),
),
body: Container(
width: 300,
child: _isLoading
? CircularProgressIndicator()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text(
'Choose Country'), // Not necessary for Option 1
value: countryValue,
onChanged: (newValue) {
setState(() {
countryValue = newValue;
});
print(countryValue);
},
items: countriesList.map((String company) {
return DropdownMenuItem(
child: new Text(company),
value: company,
);
}).toList(),
),
),
DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text('Choose City'), // Not necessary for Option 1
value: cityValue,
onChanged: (newValue) {
setState(() {
cityValue = newValue;
});
print(cityValue);
},
items: cityList.map((String company) {
return DropdownMenuItem(
child: new Text(company),
value: company,
);
}).toList(),
),
),
],
),
),
),
);
}
}
Let me know if it works.
I am trying to implement a simple news feed app using network call wherein the screen will show the latest stories in a Listview.
With the current code, I am getting a response back from the API (as I see the entire response body in the log) but can't seem to display the data in the UI. I am getting this error :
type _InternalLinkedHashMap<String, dynamic> is not subtype of type List
This is the JSON structure
{
"response": {
"status": "ok",
"userTier": "developer",
"total": 25095,
"startIndex": 1,
"pageSize": 10,
"currentPage": 1,
"pages": 2510,
"orderBy": "relevance",
"results": [
{
"id": "australia-news/2018/aug/13/turnbulls-energy-policy-hangs-in-the-balance-as-euthanasia-debate-given-precedence",
"type": "article",
"sectionId": "australia-news",
"sectionName": "Australia news",
"webPublicationDate": "2018-08-12T18:00:08Z",
"webTitle": "Energy policy hangs in balance, as Senate debates euthanasia",
"webUrl": "https://www.theguardian.com/australia-news/2018/aug/13/turnbulls-energy-policy-hangs-in-the-balance-as-euthanasia-debate-given-precedence",
"apiUrl": "https://content.guardianapis.com/australia-news/2018/aug/13/turnbulls-energy-policy-hangs-in-the-balance-as-euthanasia-debate-given-precedence",
"isHosted": false,
"pillarId": "pillar/news",
"pillarName": "News"
}, {
"id": "media/2018/jun/13/the-rev-colin-morris-obituary-letter",
"type": "article",
"sectionId": "media",
For my understanding, I just want to first display webTitle in the list, and later add other fields (after I understand the network concept clearly), but getting the error mentioned above. This is my complete code :
class MyApp extends StatelessWidget{
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Network Example',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new Scaffold(
appBar: AppBar(
title: new Text('Network Example'),
),
body: new Container(
child: new FutureBuilder<List<News>> (
future: fetchNews(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return new ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(snapshot.data[index].newsTitle,
style: new TextStyle(
fontWeight: FontWeight.bold)
),
new Divider()
],
);
}
);
} else if (snapshot.hasError) {
return new Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
),
),
);
}
Future<List<News>> fetchNews() async {
final response = await http.get('https://content.guardianapis.com/search?q=debates&api-key=');
print(response.body);
List responseJson = json.decode(response.body.toString());
List<News> newsTitle = createNewsList(responseJson);
return newsTitle;
}
List<News> createNewsList(List data) {
List<News> list = new List();
for (int i = 0; i< data.length; i++) {
String title = data[i]['webTitle'];
News news = new News(
newsTitle: title);
list.add(news);
}
return list;
}
}
class News {
final String newsTitle;
News({this.newsTitle});
factory News.fromJson(Map<String, dynamic> json) {
return new News(
newsTitle: json['webTitle'],
);
}
}
I looked at similar questions before and also went through json structures articles but can't seem to figure out how to resolve this issue.
The problem is, your JSON is not an array. It is an object. But you tried to use it as an array.
You may want to change your createNewsList call to the following:
List responseJson = json.decode(response.body.toString());
List<News> newsTitle = createNewsList(responseJson["response"]["results"]);
Mybe you can try modify this method, like this :
Future<List<News>> fetchNews() async {
final response = await http.get('https://content.guardianapis.com/search?q=debates&api-key=');
print(response.body);
List responseJson = json.decode(response.body.result);
List<News> newsTitle = createNewsList(responseJson);
return newsTitle;
}
You can use this
Map<String, String> stringParams = {};
Or
var stringParams = <String, String>{};