Deleting Firestore Data in Flutter List View - firebase

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

Related

Is there anyway to sort incoming data from StreamBuilder?

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(),
);
}
}

Flutter - How can I print all my data (fields) from firebase documents?

I would like to show all the fields of a document in firebase, but I'm having different troubles.
My intention is to show the info like a chat. I tried with a ListView.builder inside a StreamBuilder.
This is my Firestore document:
I managed to get the horizontal information using doc.data().toString but what I am trying to do is to get the whole information as a ListTile so when I add new messages they are automatically added to the ListView.builder.
This is my current code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class ChatScreen extends StatefulWidget {
const ChatScreen({Key? key}) : super(key: key);
#override
State<ChatScreen> createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final textController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(left: 20.0),
child: StreamBuilder(
stream:
FirebaseFirestore.instance.collection("messages").snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return ListTile(
title: Text(doc.data().toString()),
);
},
);
}),
),
);
}
}
And this is what I get with my current code: DeviceImage
P.S. I can get the data manually if I use this but it's not what I want:
return ListTile(
title: Text(doc['sender']),
);
Try to use an Object like below.
class Message {
final String sender;
final String text;
const Message({
required this.sender,
required this.text,
});
Map<String, dynamic> toMap() {
return {
'sender': sender,
'text': text,
};
}
factory Message.fromMap(Map<String, dynamic> map) {
return Message(
sender: map['sender'] as String,
text: map['text'] as String,
);
}
}
class ChatScreen extends StatelessWidget {
const ChatScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder<List<Message>>(
stream: FirebaseFirestore.instance
.collection("messages")
.snapshots()
.map((query) =>
query.docs.map((map) => Message.fromMap(map.data())).toList()),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final msgList = snapshot.data!;
return ListView.builder(
itemCount: msgList.length,
itemBuilder: (context, index) {
final message = msgList[index];
return ListTile(
title: Text(message.text),
leading: Text(message.sender),
);
},
);
});
}
}
Try with this.
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("messages")
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
return ListView.builder(
shrinkWrap: true,
primary: false,
itemCount: snapshot.hasData ? snapshot.data.docs.length : 0,
itemBuilder: (context, index) {
final data = MessageModel.fromSnapshot(snapshot.data.docs[index]);
return ListTile(
title: Text(data.text),
subtitle: Text(data.sender),
);
},
);
},
);
MessageModel
class MessageModel {
MessageModel({
this.sender,
this.text,
});
String sender;
String text;
String toRawJson() => json.encode(toJson());
factory MessageModel.fromSnapshot(DocumentSnapshot snapshot) {
final model =
MessageModel.fromJson(snapshot.data() as Map<String, dynamic>);
return model;
}
factory MessageModel.fromJson(Map<String, dynamic> json) => MessageModel(
sender: json["sender"] == null ? null : json["sender"],
text: json["text"] == null ? null : json["text"],
);
Map<String, dynamic> toJson() => {
"sender": sender == null ? null : sender,
"text": text == null ? null : text,
};
}

my Stream is not updating when isTeacher() function is called

what I am trying to achieve is load data from a specific collection(teacher) of my database. So I am using a function called isTeacher(). which checks if the current user's uid belongs in that collection. if not then it is a student. it stores the value in a string called value. so when I am using stream builder to load data available in their specific collection or documents, my stream builder shows circular progress and after that, it doesn't load the data. Any help is appreciated.
Thank you
`class MyClasses extends StatefulWidget {
#override
_MyClasses createState() => _MyClasses();
}
String value;
String classPassword;
List<dynamic> catchUserDetails = [];
class _MyClasses extends State<MyClasses> {
Future isTeacher() {
return FirebaseFirestore.instance
.collection('teacher')
.doc(FirebaseAuth.instance.currentUser.uid)
.get()
.then((DocumentSnapshot doc) {
value = doc.exists.toString();
print(doc.data());
print(value);
print('isteacher called in method');
});
}
#override
Widget build(BuildContext context) {
isTeacher();
return Scaffold(
body: SafeArea(
child: StreamBuilder(
stream: FirebaseFirestore.instance
.collection(value)
.doc(FirebaseAuth.instance.currentUser.uid)
.collection('class')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
} else {
final messages = snapshot.data.documents.reversed;
List<GenerateClass> messageBubbles = [];
for (var message in messages) {
final messageText = message.data()['className'];
final messageBubble = GenerateClass(
classID: messageText,
//nnouncementID: i,
);
messageBubbles.add(messageBubble);
}
return ListView(
//itemExtent: 100,
children: messageBubbles,
);
}
},
),
),
);`
Solved it by using a FutureBuilder
FutureBuilder(
future: isTeacher(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return StreamBuilder();

Store documents from firestore in list

I am trying to retrieve documents from collection called "Org" and store it in list to display in the dropdownmenu, but the list returns [Instance of 'QueryDocumentSnapshot', Instance of 'QueryDocumentSnapshot'] and thus i get following error:
The method 'map' was called on null.
Receiver: null
Tried calling: map(Closure: (dynamic) => DropdownMenuItem<dynamic>)
This is the code i implemented:
void organisation() async {
await Firebase.initializeApp();
QuerySnapshot querySnapshot = await FirebaseFirestore.instance.collection("Org").get();
final List<DocumentSnapshot> list = querySnapshot.docs;
print(list);
list.forEach((data) => print(data));
}
#override
initState() {
Firebase.initializeApp();
organisation();
super.initState();
}
This is how i implemented dropdownmenu:
DropdownButtonFormField(
validator: (value) => value == "Select" ? 'Field required' : null,
value: _selectorg,
onChanged: (val) => setState(() => _selectorg = val),
items: list.map(
(item) {
return DropdownMenuItem(
child: Text('$item'),
value: item,
);
},
).toList(),
hint: Text(
"SELECT ORGANISATION",
style: TextStyle(color: Colors.white)),
),
Try this,
#override
initState() {
super.initState();
Firebase.initializeApp();
organisation();
}
And,
Declare your list outside the function
final List<DocumentSnapshot> list;
void organisation() async {
await Firebase.initializeApp();
QuerySnapshot querySnapshot = await FirebaseFirestore.instance.collection("Org").get();
list = querySnapshot.docs;
print(list);
list.forEach((data) => print(data));
}
Update
StreamBuilder(
stream: FirebaseFirestore.instance.collection("Org").get();
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshots) {
if (snapshots.connectionState == ConnectionState.active &&
snapshots.hasData) {
print(snapshots.data);
return ListView.builder(
itemCount: snapshots.docs.length,
itemBuilder: (BuildContext context, int index) {
DocumentSnapshot doc = snapshots.data[index];
Map data= doc.data;//This is your data
return Text(
data.toString(),
);
},
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),

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