Is there anyway to sort incoming data from StreamBuilder? - firebase

Stream<QuerySnapshot> _usersStream = FirebaseFirestore.instance.collection('Listings').snapshots();
I am using this stream.
And i have streambuilder like this.
Flexible(
child: StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Error');
}
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>;
String start_location=data['start_location'];
String end_location=data['end_location'];
String date=data['date'];
String time=data['time'];
String price=data['price'];
String name_surname=data['name_surname'];
String userId=data['user_id'];
String coord=data['coord'];
var splitted=coord.split('/');
for(int i=0; i<splitted.length-1; i++){
String x = splitted[i];
var splitted2=x.split('-');
double result=calculateDistance(widget.place_latlng.latitude, widget.place_latlng.longitude, double.parse(splitted2[0]), double.parse(splitted2[1]));
if(result<1 && start_location!= widget.placename){
print("Found!");
return GestureDetector(
onTap: (){
//onTap func
},
child: buildTripCard(
context,
start_location: start_location,
end_location: end_location,
date: date,
time: time,
price: price,
name_surname: name_surname,
userId: userId,
),
);
}
}
return Container();
}).toList(),
);
},
),
)
I put into the incoming data to calculateDistance function. It returns double value (result).If that value less than 1, it shows in ListView. What i want to do is, sort Data which shows in listView order by result value.
How can i reach list that i created with .toList() method?

Sort data by chaining into stream. The below example takes all photos, which title starts with p. Converting Future to Stream is just for demonstration.
Stream<List<Photo>> photos() {
return Stream.fromFuture(
http.get(Uri.parse('https://jsonplaceholder.typicode.com/photos'))
).map((r) => parsePhotos(r.body))
.map((list) => list.where((p) => p.title.startsWith('p')).toList());
}
Then use ListView.builder to render the final list.
StreamBuilder<List<Photo>>(
stream: photos(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text('An error has occurred!'),
);
} else if (snapshot.hasData) {
final photos = snapshot.data!;
return ListView.builder(
itemCount: photos.length,
itemBuilder: (context, index) {
return Text(photos[index].title);
},
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
}

Related

Unable to retrieve firebase data to Listview

I am trying to retrieve data from my real-time firebase into a listview.
The Firebase Json Tree:
I want to retrieve Item, Expiry Date and Quantity in the listview format.
My code is as follows:
var lists = [];
final database = FirebaseDatabase(
databaseURL: "https://trackkit-a5cf3-default-rtdb.asia-southeast1.firebasedatabase.app")
.reference()
.child('Location 1');
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: StreamBuilder(
stream: database.onValue,
builder: (context, AsyncSnapshot<Event> snapshot) {
if (snapshot.hasData && !snapshot.hasError &&
snapshot.data!.snapshot.value != null) {
print("Error on the way");
lists.clear();
DataSnapshot dataValues = snapshot.data!.snapshot;
Map<dynamic, dynamic> values = dataValues.value;
values.forEach((key, values) {
lists.add(values);
});
return ListView.builder(
shrinkWrap: true,
itemCount: lists.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Item: " + lists[index]["Item"]),
Text("Expiry Date: " + lists[index]["Expiry Date"]),
Text("Quantity: " + lists[index]["Quantity"]),
],
),
);
},
);
}
return Container(child: Text("Add Items"));
},
),
),
);
}
The current screen shows :
type 'int' is not a subtype of type 'String'
I have been trying for days! Any help would be greatly appreciated.
Maybe you are getting a Integer value in return to your lists[index]["Quantity"]. And you cannot concat and integer with String without converting into a String.
So Please use method toString() with lists[index]["Quantity"] to make it work properly.
You have to Quantity make a String value, use toString() method on it in Text Widget,
like that: Text("Quantity: " + lists[index]["Quantity"].toString())

Firebase flutter _CastError (Null check operator used on a null value)

The documents on the tax page do not appear on the screen. I am getting the following _CastError (Null check operator used on a null value). Is there anyone who can help?
firestore_db_services.dart
#override
Stream<List<Vergi>> getHizmetler(String currentUserID) {
var snapShot = _firebaseFirestoreDB
.collection("hizmetler")
.doc(currentUserID)
.collection("vergi")
.orderBy("aciklamaDate")
.snapshots();
return snapShot.map(
(vergiListesi) => vergiListesi.docs
.map(
(vergi) => Vergi.fromMap(vergi.data()),
)
.toList(),
);
}
vergi.dart
Expanded(
child: StreamBuilder<List<Vergi>?>(
stream: _userModel.getHizmetler(_currentUser.userID),
builder: (context, snapShot) {
if (snapShot.hasError) {
return Center(
child: MyIndicator(),
);
}
if (snapShot.connectionState == ConnectionState.waiting) {
return Text("Yükleniyor...");
}
List<Vergi>? tumVergiListesi = snapShot.data;
return ListView.builder(
itemCount: tumVergiListesi!.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(
tumVergiListesi[index].aciklama.toString(),
),
subtitle: Text(
tumVergiListesi[index].fiyat.toString(),
),
);
},
);
},
),
),
Try returning snapshots from getHizmetler function and not the list you are currently returning:
Stream<QuerySnapshot>getHizmetler(String currentUserID) {
return _firebaseFirestoreDB
.collection("hizmetler")
.doc(currentUserID)
.collection("vergi")
.orderBy("aciklamaDate")
.snapshots();
}
Adjust your StreamBuilder like:
StreamBuilder<QuerySnapshot>(
stream: _userModel.getHizmetler(_currentUser.userID),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
// error handling
return ...;
}
if (snapshot.connectionState == ConnectionState.waiting) {
// progress indicator
return ...;
}
if (snapshot.hasData) {
// here you can do the conversion you like, result will be in:
// snapshot.data!.docs
}
}
)

data in StreamBuilder keeps returning null outside of Firebase RTDB get() call

For some reason, my data variable keeps returning null outside of my .get() call. Within the .get() call, when I print data, I get the expected map. Any insight is appreciated! The part of the code that is giving me issues are in asterisks.
class _MessagesScreenState extends State<MessagesScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: Container(
decoration: BoxDecoration(
color: Colors.white,
),
child: StreamBuilder(
stream: rtdb
.child('messages')
.child(widget.currentUserID)
.onValue,
builder: (context, snapshot) {
final messageList = <BuildMessages>[];
if (snapshot.hasData) {
final users = Map<String, dynamic>.from(
snapshot.data.snapshot.value);
users.forEach((key, value) {
**var data;**
**usersRef.child(key).get().then((value) {
data = new Map<String, dynamic>.from(value.value);
});**
final messageTile = BuildMessages(
name: data['userFirstName'] +
' ' +
data['userLastName'],
picture: data['userImageUrl'],
otherID: data['userID'],
);
;
messageList.add(messageTile);
});
}
return ListView.builder(
padding: EdgeInsets.only(top: 15.0),
itemCount: messageList.length,
itemBuilder: (context, index) {
return messageList[index];
},
);
}),
),
),
],
),
);
}
That is the expected behavior. The usersRef.child(key).get() returns a Future<DataSnapshot?>, so you'll need to wrap it into a FutureBuilder to use its value.
Based on this answer that'd be something like:
FutureBuilder<DataSnapshot?>(
future: usersRef.child(key).get(), // async work
builder: (BuildContext context, AsyncSnapshot<DataSnapshot?> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting: return Text('Loading....');
default:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
else
return Text('Result: ${snapshot.data!.value}');
}
},
)

Deleting Firestore Data in Flutter List View

I have a regular List View that fetches some data from Firestore, here is the code for it:
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('orders').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(
child:
CircularProgressIndicator(),
);
return ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.docs[index];
return Text(ds['name']);
Now if I wanted to create a delete button somewhere in it, I would do something like this:
FirebaseFirestore.instance.collection('orders').doc('ID SHOULD BE HERE').delete();
The issue I have is how do I find the document ID of the list tile on here in order to delete it automatically from the database? ID SHOULD BE HERE in the code should be some command to find the id of it like in the screenshot below:
DocumentSnapshot contains a property called id which will return the document's given ID for this snapshot. Therefore you can do the following:
itemBuilder: (context, index) {
DocumentSnapshot ds = snapshot.data.docs[index];
print(ds.id);
return Text(ds['name']);
And then to delete it according to the id, do the following:
FirebaseFirestore.instance.collection('orders').doc(ds.id).delete();
By saving the reference id from doc in local model and using the reference id on your required set of operation
I have provide the realtime example of removing the data.
class Employee {
Employee(this.employeeID, this.employeeName, this.branch, this.designation, this.location,
this.salary,
{this.reference});
double employeeID;
String employeeName;
String designation;
String branch;
String location;
double salary;
DocumentReference reference;
factory Employee.fromSnapshot(DocumentSnapshot snapshot) {
Employee newEmployee = Employee.fromJson(snapshot.data());
newEmployee.reference = snapshot.reference;
return newEmployee;
}
factory Employee.fromJson(Map<String, dynamic> json) =>
_employeeFromJson(json);
Map<String, dynamic> toJson() => _employeeToJson(this);
#override
String toString() => 'employeeName ${employeeName}';
}
Employee _employeeFromJson(Map<String, dynamic> data) {
return Employee(
data['employeeID'],
data['employeeName'],
data['branch'],
data['designation'],
data['location'],
data['salary'],
);
}
Map<String, dynamic> _employeeToJson(Employee instance) {
return {
'employeeID' : instance.employeeID,
'employeeName': instance.employeeName,
'branch': instance.branch,
'designation': instance.designation,
'location': instance.location,
'salary': instance.salary,
};
}
Repository
class EmployeeRepository{
List<Employee> employees = [];
final CollectionReference collection =
FirebaseFirestore.instance.collection('employees');
Stream<QuerySnapshot> getStream() {
return collection.snapshots();
}
Future<DocumentReference> add(Employee employee) {
var documentReference = collection.add(employee.toJson());
return documentReference;
}
update(Employee employee) async {
collection.doc(employee.reference.id).update(employee.toJson());
}
delete(Employee employee) async {
collection.doc(employee.reference.id).delete();
}
fromSnapShot(DocumentSnapshot snapshot) => Employee.fromSnapshot(snapshot);
Future<void> buildData(AsyncSnapshot snapshot) async {
if (snapshot.data.documents.length == 0) {
employees = [];
}
employees = await snapshot.data.documents.map<Employee>((doc) {
return Employee.fromSnapshot(doc);
}).toList(growable: false);
}
}
Listview builder
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Employees List'),
),
body: Column(children: [
StreamBuilder<QuerySnapshot>(
stream: employeeRepository.getStream(),
builder: (context, snapShot) {
if (!snapShot.hasData ||
snapShot.hasError ||
snapShot.connectionState == ConnectionState.waiting) {
return Container(
child: Center(child: CircularProgressIndicator()),
);
}
employeeRepository.buildData(snapShot);
return ListView.builder(
itemBuilder: (context, index) {
final employee = employeeRepository.employees[index];
return ListTile(
title: Text(employee.employeeName),
onLongPress: () {
showDialog<AlertDialog>(
context: context,
builder: (context) {
return AlertDialog(
actions: [
FlatButton(
onPressed: () {},
child: Text('Edit')),
FlatButton(
onPressed: () {
setState(() {
employeeRepository
.delete(employee);
Navigator.pop(context);
});
},
child: Text('Delete')),
],
content: Text(employee.employeeName),
);
});
},
);
},
);
}),
]),
);
}
CRUD Operation in firestore

how to get data from firebase in flutter

I am building a flutter app and using cloud-firestore,
this is how my database looks like
I want a function that retrieves all documents in the collection called "Driver List" in an array of strings
that what I had already used but it gets them back in a listview in a new screen
class DriverList extends StatelessWidget {#overrideWidget build(BuildContext context) {
return new StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('DriverList').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text('Loading...');
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document['name']),
subtitle: new Text(document['phone']),
);
}).toList(),
);
},
);
}
}
This has some additional logic to remove potentially duplicate records, but you can use something like the following to retrieve data from Firestore.
We get access to a collection reference, then list the results of the query, then create local model objects for the data returned by Firestore, and then we return the a list of those model objects.
static Future<List<AustinFeedsMeEvent>> _getEventsFromFirestore() async {
CollectionReference ref = Firestore.instance.collection('events');
QuerySnapshot eventsQuery = await ref
.where("time", isGreaterThan: new DateTime.now().millisecondsSinceEpoch)
.where("food", isEqualTo: true)
.getDocuments();
HashMap<String, AustinFeedsMeEvent> eventsHashMap = new HashMap<String, AustinFeedsMeEvent>();
eventsQuery.documents.forEach((document) {
eventsHashMap.putIfAbsent(document['id'], () => new AustinFeedsMeEvent(
name: document['name'],
time: document['time'],
description: document['description'],
url: document['event_url'],
photoUrl: _getEventPhotoUrl(document['group']),
latLng: _getLatLng(document)));
});
return eventsHashMap.values.toList();
}
Source: https://github.com/dazza5000/austin-feeds-me-flutter/blob/master/lib/data/events_repository.dart#L33
Getting one time data:
var collection = FirebaseFirestore.instance.collection('DriverList');
var querySnapshot = await collection.get();
for (var queryDocumentSnapshot in querySnapshot.docs) {
Map<String, dynamic> data = queryDocumentSnapshot.data();
var name = data['name'];
var phone = data['phone'];
}
Getting data each time it changes, using a StreamBuilder:
StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance.collection('DriverList').snapshots(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.hasData) {
final docs = snapshot.data!.docs;
return ListView.builder(
itemCount: docs.length,
itemBuilder: (_, i) {
final data = docs[i].data();
return ListTile(
title: Text(data['name']),
subtitle: Text(data['phone']),
);
},
);
}
return Center(child: CircularProgressIndicator());
},
)
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class LoadDataFromFirestore extends StatefulWidget {
#override
_LoadDataFromFirestoreState createState() => _LoadDataFromFirestoreState();
}
class _LoadDataFromFirestoreState extends State<LoadDataFromFirestore> {
#override
void initState() {
super.initState();
getDriversList().then((results) {
setState(() {
querySnapshot = results;
});
});
}
QuerySnapshot querySnapshot;
#override
Widget build(BuildContext context) {
return Scaffold(
body: _showDrivers(),
);
}
//build widget as prefered
//i'll be using a listview.builder
Widget _showDrivers() {
//check if querysnapshot is null
if (querySnapshot != null) {
return ListView.builder(
primary: false,
itemCount: querySnapshot.documents.length,
padding: EdgeInsets.all(12),
itemBuilder: (context, i) {
return Column(
children: <Widget>[
//load data into widgets
Text("${querySnapshot.documents[i].data['activation']}"),
Text("${querySnapshot.documents[i].data['car1']}"),
Text("${querySnapshot.documents[i].data['car2']}"),
Text("${querySnapshot.documents[i].data['car5']}"),
Text("${querySnapshot.documents[i].data['name']}"),
Text("${querySnapshot.documents[i].data['phone']}"),
],
);
},
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
}
//get firestore instance
getDriversList() async {
return await Firestore.instance.collection('DriversList').getDocuments();
}
}
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StreamBuilder(
stream:
FirebaseFirestore.instance.collection('messages').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
}
if (snapshot.hasData) {
final messages = snapshot.data!.docs;
List<Text> messageWigdets = [];
for (var message in messages) {
final messageText = message['text'];
final messageSender = message['sender'];
final messageWigdet =
Text('$messageText from $messageSender');
messageWigdets.add(messageWigdet);
}
return Expanded(
child: ListView(
children: [...messageWigdets],
),
);
}
return const CircularProgressIndicator.adaptive();
},
),

Resources