i am new to flutter and trying to display data from a http post
referencing from [1]https://flutter.dev/docs/cookbook/networking/background-parsing and [2]https://flutter.dev/docs/cookbook/networking/fetch-data
i tried to display data on a futurebuilder but it keeps displaying this from the Text('${snapshot.data}')
[Instance of 'DashBoardBanner', Instance of 'DashBoardBanner', Instance of 'DashBoardBanner']
Builder
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<List<DashBoardBanner>> futureBanner;
@override
void initState() {
super.initState();
futureBanner = getBannerDataFromServer();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ListView(
children: [
Card(
child: FutureBuilder(
future: getBannerDataFromServer(),
builder: (context,snapshot){
if(snapshot.connectionState == ConnectionState.done){
if (snapshot.hasData) {
return Text('${snapshot.data}');
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
}
return const CircularProgressIndicator();
},
),
)
],
)),
);
}
}
Class and postreq
class DashBoardBanner {
final String MsgId;
final String MsgKey;
final String MsgPic;
const DashBoardBanner(
{required this.MsgId, required this.MsgKey, required this.MsgPic});
factory DashBoardBanner.fromJson(Map<String, dynamic> json) {
return DashBoardBanner(
MsgId: json['MsgId'] as String,
MsgKey: json['MsgKey'] as String,
MsgPic: json['MsgPic'] as String,
);
}
}
Future<List<DashBoardBanner>> getBannerDataFromServer() async {
final queryParameters = {
"ApiFunc": 'Banner',
"UserKey": getDeviceKey(),
"Token": getDeviceToken(),
"SubmitContent": json.encode({"MobileNo": getMobileNo1()})
};
final response = await http.post(
Uri.http('somesite.net', '/capi.aspx', queryParameters),
);
if (response.statusCode == 200) {
Map<String, dynamic> data = jsonDecode(response.body);
final splitoff = jsonEncode(data['RespContent']);
return compute(parseBanner, splitoff);
} else {
throw Exception('Failed to load Data');
}
}
List<DashBoardBanner> parseBanner(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();
return parsed
.map<DashBoardBanner>((json) => DashBoardBanner.fromJson(json))
.toList();
}
Edit : i rebuilt the file replicating reference[1] and it finally displayed the data i needed, it seems the issue stem from not having this 2nd widget which return the obj back , however how do i combine the 2nd build widget into the first without needing the whole widget as having a whole build widget to return 1 line seems pointless?
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body:Container(
child: FutureBuilder<List<DashBoardBanner>>(
future: getBannerDataFromServer(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text('An error has occurred!'),
);
} else if (snapshot.hasData) {
print(snapshot.data!.length);
return DashBoardBannersList(dashboardBanners: snapshot.data!); <--- original issue due to not having this
} else {
return CircularProgressIndicator();
}
},
),
),
);
}
}
class DashBoardBannersList extends StatelessWidget {
const DashBoardBannersList({Key? key, required this.dashboardBanners}) : super(key: key);
final List<DashBoardBanner> dashboardBanners;
@override
Widget build(BuildContext context) {
return Text(dashboardBanners[0].MsgId);
}
}
CodePudding user response:
This error is caused because of the sound null safety
snapshot.data might be null for some requests so you can't access the array at a certain index cause it can be null. If you know for sure snapshot.data exists you can use the ! operator to tell dart the variable is not null for sure like that:
snapshot.data![index];
You can also check if the data is null before accessing it like that:
if (snapshot.data != null) {
// do something with snapshot.data[index]
}
I recommed to read more about sound null safety here
CodePudding user response:
Check the Firestore docs.
Inside snapshot.data
, there's docs
(every document of your collection).
The code is from there:
@override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
return ListTile(
title: Text(data['full_name']),
subtitle: Text(data['company']),
);
}).toList(),
);
},
);
}
The code above shows how to convert every doc (type DocumentSnapshot) to a JSON format (that can be represented with Map<String, dynamic>
). To access to the doc id
, you'll access with document.id
, because it isn't inside the document.data()
method.
CodePudding user response:
You wanna retrieve a list of DashBoardBanner but you forget initialize the futurebuilder by adding a ListView.builder().
Try to use the following code idea :
FutureBuilder(
future: getBannerDataFromServer(http.Client()),
builder: (context, AsyncSnapshot snapshot) {
print(snapshot.hasData);
if (snapshot.hasError) {
return CircularProgressIndicator();
} else if (snapshot.hasData) {
return Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
var data = snapshot.data![index];
return DashBoardBannersList(dashboardBanners: data);
},),
),},
},)