Cannot display fetched data to the UI in Flutter - flutter

I tried to fetch data as List from database but data not display in UI. How I fix this? I tried fetch data using model class and my collection name is '12words'.
UI code:
class _WordsScreenState extends State<WordsScreenState> {
List<Words12> wordList = [];
#override
void iniState() {
fetchRecords();
iniState();
}
fetchRecords() async {
var records = await FirebaseFirestore.instance.collection('12words').get();
mapRecords(records);
}
mapRecords(QuerySnapshot<Map<String, dynamic>> records) {
var _list = records.docs
.map(
(words12) => Words12(
id: words12.id,
wordName: words12['wordName'],
categoryName: words12['categoryName'],
),
)
.toList();
setState(() {
wordList = _list;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: ListView.builder(
itemCount: wordList.length,
itemBuilder: (context, index) {
return (ListTile(
title: Text(wordList[index].wordName),
subtitle: Text(wordList[index].categoryName),
));
},
));
}
Model:

First do not call async function in initState, instead of that, use FutureBuilder and also change your fetchRecords() to return a list. This is a full example of using FutureBuilder with your code:
class TestFuture extends StatefulWidget {
const TestFuture({super.key});
#override
State<TestFuture> createState() => _TestFutureState();
}
class _TestFutureState extends State<TestFuture> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: FutureBuilder<List<Words12>>(
future: fetchRecords(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List<Words12> data = snapshot.data ?? [];
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return (ListTile(
title: Text(data[index].wordName),
subtitle: Text(data[index].categoryName),
));
},
);
}
}
},
),
);
}
Future<List<Words12>> fetchRecords() async {
var records = await FirebaseFirestore.instance.collection('12words').get();
return mapRecords(records);
}
List<Words12> mapRecords(QuerySnapshot<Map<String, dynamic>> records) {
var _list = records.docs
.map(
(words12) => Words12(
id: words12.id,
wordName: words12['wordName'],
categoryName: words12['categoryName'],
),
)
.toList();
return _list;
}
}

Related

Create ListView Builder from StreamBuilder with ISAR Database

I am trying to create a ListView Builder from Stream builder in Flutter.
TodoList Class
import 'package:isar/isar.dart';
part 'todo_list.g.dart';
#Collection()
class TodoList {
Id id = Isar.autoIncrement;
late String todoTitle;
}
Isar Services
class IsarService {
late Future<Isar> db;
IsarService() {
db = openDB();
}
//Return IsarDB, if not found, then create
Future<Isar> openDB() async {
if (Isar.instanceNames.isEmpty) {
return await Isar.open(
[TodoListSchema],
inspector: true,
);
}
return Future.value(Isar.getInstance());
}
Stream<List<TodoList>> listenToTodoList() async* {
final isar = await db;
yield* isar.todoLists.where().watch(fireImmediately: true);
}
}
ListView Builder from above Streambuilder
class ListScreen extends StatefulWidget {
final IsarService service;
const ListScreen(this.service, {super.key});
#override
State<ListScreen> createState() => _ListScreenState();
}
class _ListScreenState extends State<ListScreen> {
//Text Controller
final _textController = TextEditingController();
final service = IsarService();
//Let's build List Title from snapshot
final List<TodoList> _todoList = [];
//Root widget of the class
#override
Widget build(BuildContext context) {
return Scaffold(
//List Screen Body Section
body: StreamBuilder(
stream: service.listenToTodoList(),
builder: (context, snapshot) {
if (snapshot.hasError) {
AlertDialog(
content: Text(snapshot.error.toString()),
);
} else if (snapshot.hasData) {
_todoList.add(snapshot.data); //Error happen in this line
}
return const CircularProgressIndicator();
},
),
);
}
}
The Error is
The argument type 'List?' can't be assigned to the parameter type 'TodoList'.
I'am trying to assign the snapshot data in final List<TodoList> _todoList = []; and use them ListView Builder
Try this code:
return Scaffold(
body: StreamBuilder(
stream: service.listenToTodoList(),
builder: (context, snapshot) {
if (snapshot.hasError) {
AlertDialog(
content: Text(snapshot.error.toString()),
);
} else if (snapshot.hasData) {
final todos = snapshot.data;
if (todos != null) {
return ListView.builder(
itemCount: todos.length();
itemBuilder: (context, index) {
final todo = todos[index];
return Text(todo.todoTitle);
}
);
} else {
return const Center(child: Text('No data found!'));
}
}
return const CircularProgressIndicator();
},
),
);

How to use querySnapshot in a listview builder? (flutter)

I'm trying to fetch documents from my firebase DB and use them to create a social media feed. Here I'm trying to get the length of the fetched collection but I cannot manage to call the variable. Any help would be appreciated. Example code
class LoadDataFromFirestore extends StatefulWidget {
#override
_LoadDataFromFirestoreState createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
#override
void initState() {
super.initState();
CollectionReference _collectionRef =
FirebaseFirestore.instance.collection('fish');
Future<void> getData() async {
// Get docs from collection reference
QuerySnapshot querySnapshot = await _collectionRef.get();
// Get data from docs and convert map to List
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
}
}
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: querySnapshot.docs.length,
itemBuilder: (BuildContext context, int index) {
return _postView();
},
),
);
}
}
First of all it is not ok to call future function in initstate, you need to use FutureBuilder like this:
class LoadDataFromFirestore extends StatefulWidget {
#override
_LoadDataFromFirestoreState createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
late CollectionReference _collectionRef;
#override
void initState() {
super.initState();
_collectionRef = FirebaseFirestore.instance.collection('fish');
}
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<QuerySnapshot>(
future: _collectionRef.get(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
QuerySnapshot? querySnapshot = snapshot.data;
return ListView.builder(
itemCount: querySnapshot?.docs?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
var data = querySnapshot?.docs?[index].data();
print("data = $data");
return _postView();
},
);
}
}
},
),
);
}
}
inside listview's builder you can use data to parse your data and use it.
You can use FutureBuilder like this:
class LoadDataFromFirestore extends StatefulWidget {
const LoadDataFromFirestore({super.key});
#override
State<LoadDataFromFirestore> createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
//TODO change Map<String, dynamic> with your data type with fromJson for example
Future<List<Map<String, dynamic>>> _getData() async {
final querySnapshot = await FirebaseFirestore.instance.collection('fish').get();
return querySnapshot.docs.map((doc) => doc.data()).toList();
}
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Map<String, dynamic>>>(
future: _getData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return _postView(/* Ithink you have to pass here your item like snapshot.data[index]*/);
},
);
} else {
return const Center(child: CircularProgressIndicator());
}
},
),
);
}
}

Retrieving Firestore data in ListView but Failing

Currently struggling to make a ListView data retrieved from Firestore.
I am trying to get "kids name" saved under in the firestore as linked photo.
Firestore
No error message is shown up but the data is not retrieved correctly and shown blank screen...hope anyone can correct my code!
and here is my code:
class kidsNamePick extends StatefulWidget {
#override
_kidsNamePickState createState() => _kidsNamePickState();
}
class _kidsNamePickState extends State<kidsNamePick> {
List<Memo> kidsnamelist = [];
Future<void>fetchMemo()async{
final kidsnames = await FirebaseFirestore.instance.collection('useraccount').doc(FirebaseAuth.instance.currentUser!.uid)
.collection('kidsname').get();
final docs = kidsnames.docs;for (var doc in docs){
Memo fetchMemo = Memo(kidsname: doc.data()['kids name'],
);
kidsnamelist.add(fetchMemo);}
setState(() {
});}
#override
void initState(){
super.initState();
fetchMemo();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Add/Select Kids'),
),
body: ListView.builder(
itemCount: kidsnamelist.length,
itemBuilder: (context, index){
return ListTile(
title: Text(kidsnamelist[index].kidsname),
);
},
)
);
}
}
The best way to call future method is using FutureBuilder, first change your fetchMemo to this:
Future<List<Memo>> fetchMemo() async {
try {
final kidsnames = await FirebaseFirestore.instance
.collection('useraccount')
.doc(FirebaseAuth.instance.currentUser!.uid)
.collection('kidsname')
.get();
final docs = kidsnames.docs;
return docs
.map((doc) => Memo(
kidsname: doc.data()['kids name'],
))
.toList();
} catch (e) {
return [];
}
}
then change your build method to this:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Add/Select Kids'),
),
body: FutureBuilder<List<Memo>>(
future: fetchMemo(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List<Memo> data = snapshot.data ?? [];
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(data[index].kidsname),
);
},
);
}
}
},
),
);
}

How can I fetch images from api into card widget in flutter?

I'm trying to fetch api images into the card widgets in flutter. I have services, model and photos_page class. I tried lot's of ways but still doesn't work.
final photoItem = snapshot.data[index].previewURL;
I think problem is that snapshot can't get data
that's my photos_page:
import 'dart:convert';
import 'package:abcde/services/photos_model.dart';
import 'package:abcde/services/photos_service.dart';
import 'package:abcde/widgets/card_widget.dart';
import 'package:flutter/material.dart';
class PhotosPage extends StatefulWidget {
PhotosPage({Key? key}) : super(key: key);
static const String pathId = 'Photos page';
#override
State<PhotosPage> createState() => _PhotosPageState();
}
class _PhotosPageState extends State<PhotosPage> {
PhotosService photosService = PhotosService();
#override
void initState() {
// TODO: implement initState
super.initState();
photosService.getPhotos();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Photos'),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: [
_getProductTypeList(),
]),
),
);
}
Widget _buildListItem(
BuildContext context, AsyncSnapshot<dynamic> snapshot, int index) {
final photoItem = snapshot.data[index].previewURL;
print('photoItem is $photoItem');
return photoCard(photoItem);
}
Widget _buildList(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
var values = snapshot.data;
return ListView.builder(
// itemCount: snapshot.length,
itemBuilder: (context, index) {
return _buildListItem(context, snapshot, index);
},
);
/* return ListView(
children: snapshot!.map((data) => _buildListItem(context, data)).toList(),
);*/
}
//PhotosModel photosModel = PhotosModel();
Widget _getProductTypeList() {
return Expanded(
child: FutureBuilder(
future: photosService.getPhotos(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: LinearProgressIndicator(),
);
}
return _buildList(context, snapshot);
},
),
);
}
}
that's my model class:
class PhotosModel {
String previewURL;
PhotosModel({required this.previewURL});
/* factory PhotosModel.fromJson(Map<dynamic, dynamic> json) => PhotosModel(
previewURL: json['previewURL'] as String,
);
Map<String, dynamic> toJson() {
return <String, dynamic>{'previewURL': previewURL};
}*/
/* #override
String toString() {
return 'PhotosModel{url: $previewURL}';
}*/
/*factory PhotosModel.fromJson(Map<String, dynamic> json) {
return PhotosModel(url: json['url'] as String);
}*/
factory PhotosModel.fromJson(Map<dynamic, dynamic> json) =>
_commentFromJson(json);
Map<dynamic, dynamic> toJson() => photosModelToJson(this);
}
PhotosModel _commentFromJson(Map<dynamic, dynamic> json) {
return PhotosModel(
previewURL: json['previewURL'],
);
}
Map<dynamic, dynamic> photosModelToJson(PhotosModel instance) => <dynamic, dynamic>{
'previewURL': instance.previewURL,
};
and that's my service class. I make a list getPhotos() method but doesn't work anyway.
import 'dart:convert';
import 'package:abcde/services/photos_model.dart';
import 'package:http/http.dart';
const MY_API_KEY = '26711456-bde74f403cb42e77029bc1678';
const appUrl = 'https://pixabay.com/api/';
class PhotosService {
Future getData(String url) async {
print('Calling url: $url');
final response = await get(Uri.parse(url));
if (response.statusCode == 200) {
return response.body;
} else {
print(response.statusCode);
}
}
List<PhotosModel> dataList = [];
Future<List<PhotosModel>> getPhotos({String? query}) async {
final photosData = await getData(
'$appUrl?&key=$MY_API_KEY&q=$query');
var data =json.decode(photosData);
data.forEach((element) {
dataList.add(PhotosModel.fromJson(element));
});
print('this is photos data: $photosData');
return dataList;
}
}
that's the error it shows me
The following NoSuchMethodError was thrown building:
The method '[]' was called on null.
Receiver: null
Tried calling:
and that's my card widget
import 'package:flutter/material.dart';
Widget photoCard(String url) {
return Card(
child: Image(
image: NetworkImage(url),
),
);
}
for api I use this web-page:
https://pixabay.com/api/docs/#api_search_images
thank you very much in advance
Working Example
main.dart
===============
import 'package:demo_app/photo_page.dart';
import 'package:flutter/material.dart';
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 Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const PhotosPage(),
);
}
}
==============
photo_service.dart
====================
import 'dart:convert';
import 'package:http/http.dart';
const apiKey = '26711456-bde74f403cb42e77029bc1678';
const appUrl = 'https://pixabay.com/api/';
class PhotosService {
Future getData(String url) async {
print('Calling url: $url');
final response = await get(Uri.parse(url));
if (response.statusCode == 200) {
return response.body;
} else {
print(response.statusCode);
}
}
List<PhotosModel> dataList = [];
Future<List<PhotosModel>> getPhotos(String query) async {
final photosData = await getData('$appUrl?key=$apiKey&q=$query');
var data = json.decode(photosData);
var items = data["hits"];
items.forEach((element) {
dataList.add(PhotosModel.fromJson(element));
});
print('this is photos data: $photosData');
return dataList;
}
}
class PhotosModel {
String previewURL;
PhotosModel({required this.previewURL});
factory PhotosModel.fromJson(Map<dynamic, dynamic> json) =>
_commentFromJson(json);
Map<dynamic, dynamic> toJson() => photosModelToJson(this);
}
PhotosModel _commentFromJson(Map<dynamic, dynamic> json) {
return PhotosModel(
previewURL: json['previewURL'],
);
}
Map<dynamic, dynamic> photosModelToJson(PhotosModel instance) =>
<dynamic, dynamic>{
'previewURL': instance.previewURL,
};
=========================
photo_page.dart
=============
import 'package:demo_app/photo_service.dart';
import 'package:flutter/material.dart';
class PhotosPage extends StatefulWidget {
const PhotosPage({Key? key}) : super(key: key);
static const String pathId = 'Photos page';
#override
State<PhotosPage> createState() => _PhotosPageState();
}
class _PhotosPageState extends State<PhotosPage> {
PhotosService photosService = PhotosService();
#override
void initState() {
super.initState();
photosService.getPhotos("flower");
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Photos'),
),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: [
_getProductTypeList(),
]),
),
);
}
Widget _buildListItem(
BuildContext context, AsyncSnapshot<dynamic> snapshot, int index) {
final photoItem = snapshot.data[index].previewURL;
print('photoItem is $photoItem');
return photoCard(photoItem);
}
Widget _buildList(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
var values = snapshot.data;
return ListView.builder(
itemCount: snapshot.hasData ? snapshot.data.length : 0,
itemBuilder: (context, index) {
return _buildListItem(context, snapshot, index);
},
);
}
Widget _getProductTypeList() {
return Expanded(
child: FutureBuilder(
future: photosService.getPhotos("flower"),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: LinearProgressIndicator(),
);
}
return _buildList(context, snapshot);
},
),
);
}
}
Widget photoCard(String url) {
return Card(
child: Image(
image: NetworkImage(url),
),
);
}

how to access snapshot.data inside Listview.builder inside futurebuilder

I am getting error The method '[]' can't be unconditionally invoked because the receiver can be 'null'.
Mydata inside _categoriesList future
[
{
"business_category_id": 1,
"business_category": "Manufacturer",
"business_category_image": "164423936662011a06c450d.png"
},
{
"business_category_id": 2,
"business_category": "Distributor",
"business_category_image": "164423937762011a11033aa.png"
},
{
"business_category_id": 3,
"business_category": "Wholesaler",
"business_category_image": "164423938762011a1bb2e3c.png"
},
{
"business_category_id": 4,
"business_category": "Retailer",
"business_category_image": "164423940062011a28189e5.png"
},
{
"business_category_id": 5,
"business_category": "Reseller",
"business_category_image": "164423941362011a3554148.png"
},
{
"business_category_id": 6,
"business_category": "Service Provider",
"business_category_image": "164423942462011a4096996.png"
}
]
my code inside futurebuilder. I am having problem accessing snapshot.data[index]
FutureBuilder(
future: _categoriesList,
builder: (_, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: 6,
itemBuilder: (_, index) {
return Text(snapshot.data[index]); // error The method '[]' can't be unconditionally invoked because the receiver can be 'null'
});
}
},
)
Here is the example for ListView.builder:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future <List<Data>> fetchData() async {
final response =
await http.get('https://jsonplaceholder.typicode.com/albums');
if (response.statusCode == 200) {
List jsonResponse = json.decode(response.body);
return jsonResponse.map((data) => new Data.fromJson(data)).toList();
} else {
throw Exception('Unexpected error occured!');
}
}
class Data {
final int userId;
final int id;
final String title;
Data({this.userId, this.id, this.title});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Future <List<Data>> futureData;
#override
void initState() {
super.initState();
futureData = fetchData();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter API and ListView Example',
home: Scaffold(
appBar: AppBar(
title: Text('Flutter ListView'),
),
body: Center(
child: FutureBuilder <List<Data>>(
future: futureData,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Data> data = snapshot.data;
return
ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 75,
color: Colors.white,
child: Center(child: Text(data[index].title),
),);
}
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default show a loading spinner.
return CircularProgressIndicator();
},
),
),
),
);
}
}
Specify your data-type for list in FutureBuilder first.
FutureBuilder<List<String>>()
//
Check if you are getting data. print the data using snapshot.data.
FutureBuilder<List<String>>(
future: _categoriesList,
builder: (_, snapshot) {
if (snapshot.hasData) {
print("snapshot:: data >>>> ${snapshot.data}");
return ListView.builder(
itemCount: 6,
itemBuilder: (_, index) {
return Text(snapshot.data[index]); // error The method '[]' can't be unconditionally invoked because the receiver can be 'null'
});
}
},
)
Assuming you have a Category class, with variables for the CategoryId,CategoryName,CategoryImage with all the needed methods as shown in https://stackoverflow.com/a/71029334/12371668
//create an instance of the category class before the build() method
final category = Category();
#override
Widget build(BuildContext context) {
// other code
FutureBuilder(
future: category.fetchData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Category> categories = snapshot.data();
return ListView.builder(
itemCount: categories.length,
itemBuilder: (context, index) {
var category = categories[index];
return Text(category.CategoryName);
});
}
},
)
}