Fetching data from Firebase into listview in flutter - flutter

I'm trying to fetch data from firebase and I want that data to be printed in my listview.builder.
Here is my code:-
StreamBuilder(
stream: FirebaseFirestore.instance
.collection("passwordProfile")
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
if (snapshot.data.documents.lenght == 0) {
return Text("no data");
}
return ListView.builder(
itemCount: snapshot.data.documents.lenght,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
child: snapshot.data.documents[index].data("url")),
title: snapshot.data.documents[index].data["url"],
);
});
}),
And below is a picture:-
From the picture you can observe that documents is not being recognized so help there.

Please specify SteamBuilder return type i-e Querysnapshot here's the example of your code
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("passwordProfile")
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
final userSnapshot = snapshot.data?.docs;
if (userSnapshot!.isEmpty) {
return const Text("no data");
}
return ListView.builder(
itemCount: userSnapshot.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(
child: userSnapshot[index]["url"],
),
title: userSnapshot[index]["url"],
);
});
});

Once you check null, you can add ! like snapshot.data!
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
final data = snapshot.data as Map<String, dynamic>?;
if (data == null) {
return Text("no data");
}
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return ListTile(
// leading:
// CircleAvatar(child: data[index].data("url")),
title: Text("${data[index].data["url"]}"),
);
});
}),

Related

Why when i add data to firebase, the data keep looping?

I'm new to flutter and firebase and I do not know why when I upload any data to firebase the data will keep repeating the same thing but when I hot restart the upload item back to 1, this is my code:
Future getDocId() async {
await FirebaseFirestore.instance
.collection('users')
.orderBy('mobile', descending: true)
.get()
.then(
(snapshot) => snapshot.docs.forEach(
(document) {
print(document.reference);
docIDs.add(document.reference.id);
},
),
);
}
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: FutureBuilder(
future: getDocId(),
builder: (context, snapshot) {
return ListView.builder(
itemCount: docIDs.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: ListTile(
title: ReadUser(documentId: docIDs[index]),
tileColor: Colors.purple[100],
),
);
},
);
},
),
),
This is my future builder
return FutureBuilder<DocumentSnapshot>(
future: users.doc(documentId).get(),
builder: ((context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Text('Name:' +
'${data['name']}' +
"\n"
'Email:' +
'${data['email']}' +
"\n"
'Mobile Number:' +
'+' +
'${data['mobile']}' +
"");
}
return Text('Loading..');
}),
);
the way you are fetching your data is wrong, instead of pass the result into outside variable you need to return it like this, I assume docIDs is a list of string:
Future<List<String>> getDocId() async {
try {
var snapshot = await FirebaseFirestore.instance
.collection('users')
.orderBy('mobile', descending: true)
.get();
return snapshot.docs.map((document) => document.reference.id).toList();
} catch (e) {
return [];
}
}
then change your FutureBuilder to this:
FutureBuilder<List<String>>(
future: getDocId(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List<String> data = snapshot.data ?? [];
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: ListTile(
title: ReadUser(documentId: data[index]),
tileColor: Colors.purple[100],
),
);
},
);
}
}
},
),

convert this into streambuilder in flutter

I want to convert this function into Streambuilder, but somehow I could not figure out how I could do it. Any help would be greatly appreciated.
Future getReceiverChats() async {
var data = await FirebaseFirestore.instance
.collection("message")
.doc(widget.id)
.collection("nodes")
.orderBy("time", descending: false)
.get();
setState(() {
_msgReceiverList =
List.from(data.docs.map((doc) => Message.fromMap(doc)));
});
}
Try this:
Stream<List<Message>> getReceiverChats(String id) {
return FirebaseFirestore.instance
.collection("message")
.doc(id)
.collection("nodes")
.orderBy("time", descending: false)
.snapshots()
.map((QuerySnapshot query) {
List<Message> dataList = [];
query.docs.forEach((doc) {
dataList
.add(Message.fromMap(doc));
});
return dataList;
});
}
Then:
StreamBuilder<List>(
stream: getReceiverChats(widget.id),
builder: (context, snapshot) {
if (snapshot.hasData) {
final List<Message>? dataList = snapshot.data;
if (dataList!.isEmpty) {
return Center(
child: Text('No results'),
);
}
return ListView.builder(
itemCount: dataList.length,
itemBuilder: (context, index) {
return MyWidget(dataList[index]);
});
}
if (snapshot.connectionState == ConnectionState.done) {
if (!snapshot.hasData) {
return Center(
child: Text('No results'),
);
}
}
return const Center(
child: CircularProgressIndicator(),
);
})
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("message")
.doc(widget.id)
.collection("nodes")
.orderBy("time", descending: false)
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Error: ${snapshot.error}");
}
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text("Loading...");
default:
return ListView(
children: snapshot.data.docs.map((doc) {
return Message.fromMap(doc);
}).toList(),
);
}
},
),

Modify Future Builder inside Stream Builder to avoid widget flickering

I am using a FutureBuilder inside a StreamBuilder that updates the UI every time a document is added to the activity collection, to get some aditional data from Firestore. The problem is that the FutureBuilder returns a SizedBox widget while the ConnectionState is waiting causing the all the cards to dissapear for a second. I would like to avoid this flickering since it causes a bad ui experience for users.
Is there a way to query the required user data in the activity stream so it all returns at once that way I can remove the FutureBuilder?
If not ... what would be a solution for this?
activityStream() {
return FirebaseFirestore.instance
.collection('activity')
.orderBy('timestamp', descending: true)
.limit(55)
.snapshots();
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const SizedBox(
height: 65.0,
);
}
StreamBuilder<QuerySnapshot>(
stream: activityStream(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const Center(child: CircularProgressIndicator());
default:
final activityContent = snapshot.data?.docs
.map((data) => ActivityModel.fromFirestore(data))
.toList();
return Scrollbar(
controller: widget.scrollController,
child: ListView.builder(
shrinkWrap: true,
controller: widget.scrollController,
itemCount: activityContent!.length,
itemBuilder: (context, i) {
return FutureBuilder(
future: FirebaseFirestore.instance
.collection('users')
.where('uid', whereIn: activityContent[i].players)
.get(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const SizedBox(
height: 65.0,
);
}
final users = snapshot.data!.docs.map((e) {
return UserModel.fromFirestore(e);
}).toList();
return MyWidget(
users: users,
);
},
);
},
),
);
}
},
);

How do I add null check to data shown in my code?? Flutter Firestore Query Snapshot

StreamBuilder<QuerySnapshot>(
initialData: null,
stream: FirebaseFirestore.instance
.collection('tasks')
// .where('date', isEqualTo: date.dateTimeSelected.toString())
.snapshots(includeMetadataChanges: true),
builder: (context, snapshot) {
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else if (snapshot.hasData) {
print(snapshot.data!.docs.length);
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
default:
print(snapshot.data!.docs);
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (ctx, i) => Meetingcard(
id: snapshot.data!.docs[i].data()["id"],
title: snapshot.data!.docs[i].data()["title"],
description:
snapshot.data!.docs[i].data()["description"],
time: snapshot.data!.docs[i].data()["timeStart"],
),
itemCount: snapshot.data!.docs.length,
);
\
}
} else {
return Text("No Data");
}
},
How do i add null check in the line snapshot.data!.docs[i].data()["description"]
enter image description here

Update ListView.builder itemCount when firestore document is added

I have a flutter app where a list is generated with ListView.Builder, and where the itemCount is the number of documents in a firestore collection. This works fine until a new document is added. When that happens I get the error (17 and 18 are just examples).
Invalid value: Not in range 0..17, inclusive: 18
I assume I would need to update the state when a new document is created, but I have no idea how i can call setState when that happens
Here is the relevant part of the code:
child: StreamBuilder(
stream: Firestore.instance.collection('contact').orderBy(sortby, descending: decending).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Container();
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_personer(context, snapshot.data.documents[index], index),
);
},
),
use setState?
StreamBuilder(builder: (context, snapshot) {
return snapshot.hasData == null ? Container() : _getListView(snapshot);
} , )
_getListView(snapshot) {
setState(() {
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_personer(context, snapshot.data.documents[index], index),
);
});
}
StreamBuilder use QuerySnapshot so list data can change
example code :
StreamBuilder<QuerySnapshot>(
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting: return new Text('Loading...');
default:
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
return ;
}).toList(),
);
}
},
)