enter image description here
Trying already for a couple of days to get document id of a document in Firestore from my Flutter app.
what I want is to update or delete document, but have to identify it first by his id.
I have that ID with other values like name, address, etc.., when I open Firestore.
Now I am trying to understand how to get document id into a variable, which I then use in my function to delete or update the document.
getDocIndex() {
var documentID = Firestore.instance
.collection('Requests')
.document(widget.data['Document ID'].toString())
.get();
print(documentID);
}
I understand that widget in a function is not usable. Maybe something with snapshot.data.... but its also marked as red.
This is my function which then should work:
deleteDocument(){
Firestore.instance.collection('Requests').document(documentID).delete();
}
enter image description here
enter image description here
If you know the values inside the document, you can use a where query to find all documents that have those parameters.
Firestore.instance.collection('requests').where('Document ID', isEqualTo: "ID")
.snapshots().listen(
(data) => print('grower ${data.documents[0]['name']}')
);
However, if you already have access to the document's data locally, you can pull the reference path from the document snapshot if you have stored it locally. It is only an issue of recovering that data from within your app at that point.
Thank you all! I've got it!
return ListTile(
title: Text(
'${snapshot.data[index].data['Name']}',
style: GoogleFonts.lexendDeca(),
),
subtitle: Text(
'${snapshot.data[index].data['Anfrage vom']}',
style: GoogleFonts.lexendDeca(),
),
onTap: () {
navigateToDetail(snapshot.data[index]);
keyID = snapshot.data[index].data['Document ID'];
print(keyID.toString());
Below I get in keyID the Document ID from field in a document. After that I can use the delete function with ID reference.
Firestore.instance.collection('Requests').document(keyID).delete();
getDocIndex() {
var document = Firestore.instance
.collection('Requests')
.document(widget.data['Document ID'].toString())
.get();
print(document.id);
}
getDocIndex() async {
var document = await Firestore.instance
.collection('Requests')
.document(widget.data['Document ID'].toString())
.get();
print(document.id);
}
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:kuechenrechner/card_widget.dart';
import 'package:kuechenrechner/gmaps.dart';
import 'package:geocoder/geocoder.dart';
import 'adminslogin.dart';
//final documentsRef = Firestore.instance.collection('Requests');
class Admins extends StatefulWidget {
#override
_AdminsState createState() => _AdminsState();
}
class _AdminsState extends State<Admins> {
/*geoConvert() async {
// Geocoding for Address
// final query = "1600 Amphiteatre Parkway, Mountain View";
var addresses = await Geocoder.local.findAddressesFromQuery(query);
var first = addresses.first;
print("${first.featureName} : ${first.coordinates}");
}
*/
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return AdminsLogin();
}));
}),
title: Text(
'Anfragen',
style: GoogleFonts.lexendDeca(),
),
centerTitle: true,
actions: [
IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
setState(() {});
})
],
),
body: AdminsList(),
);
}
}
Future getPosts() async {
var firestore = Firestore.instance;
QuerySnapshot qn = await firestore
.collection("Requests")
.orderBy('Anfrage vom')
.getDocuments();
return qn.documents;
}
//Abfrage DocumentID
getDocIndex() async {
/* var documentID = Firestore.instance
.collection('Requests')
.document(widget.data['Document ID'].toString())
.get();
print(documentID);
*/
var document = await Firestore.instance
.collection('Requests')
.document(widget.data['Document ID'].toString())
.get();
print(document.id);
}
class AdminsList extends StatefulWidget {
#override
_AdminsListState createState() => _AdminsListState();
}
class _AdminsListState extends State<AdminsList> {
navigateToDetail(DocumentSnapshot post) {
Navigator.push(context,
MaterialPageRoute(builder: (context) => AdminsDetails(post: post)));
}
#override
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: getPosts(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: Text('Loading...'),
);
} else {
return ListView.separated(
reverse: true,
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return ListTile(
title: Text(
'${snapshot.data[index].data['Name']}',
style: GoogleFonts.lexendDeca(),
),
subtitle: Text(
'${snapshot.data[index].data['Anfrage vom']}',
style: GoogleFonts.lexendDeca(),
),
onTap: () => navigateToDetail(snapshot.data[index]),
leading: Icon(
Icons.business_center,
color: Colors.blue,
),
trailing: IconButton(
icon: Icon(Icons.sort),
onPressed: () {
getDocIndex();
}),
);
},
separatorBuilder: (BuildContext context, int index) {
return Divider();
},
);
}
}),
);
}
}
class AdminsDetails extends StatefulWidget {
final DocumentSnapshot post;
AdminsDetails({this.post});
#override
_AdminsDetailsState createState() => _AdminsDetailsState();
}
String keyID;
class _AdminsDetailsState extends State<AdminsDetails> {
//Anfragen löschen intern
deleteDocument() async {
/* CollectionReference collectionReference =
Firestore.instance.collection("Requests");
QuerySnapshot querySnapshot = await collectionReference.getDocuments();
querySnapshot.documents[0].reference.delete();
*/
Firestore.instance.collection('Requests').document(keyID).delete();
}
//Anfragen intern ändern, anpassen! Button in der Appbar!
TextEditingController adminComment = TextEditingController();
updateData() async {
CollectionReference collectionReference =
Firestore.instance.collection("Requests");
QuerySnapshot querySnapshot = await collectionReference.getDocuments();
querySnapshot.documents[0].reference
.updateData({'Administrator Anmerkung': adminComment.text});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Anfrage von ${widget.post.data["Name"]}',
style: GoogleFonts.lexendDeca(),
),
centerTitle: true,
actions: [
IconButton(
icon: Icon(Icons.edit),
onPressed: () {
setState(() {
updateData();
});
})
],
),
body: SingleChildScrollView(
child: Container(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Kontaktdaten des Kunden: ',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w200),
),
TextButton(
onPressed: () => customLaunch(
'mailto:${widget.post.data["Email"]}?subject=Feed%20back&body=Write your%20feedback'),
child: Text('Email: ${widget.post.data["Email"]}',
style: TextStyle(fontSize: 18)),
),
SizedBox(
child: Container(color: Colors.amber),
),
TextButton(
onPressed: () =>
customLaunch('tel: ${widget.post.data["Telefon"]}'),
child: Text('Telefon: ${widget.post.data["Telefon"]}',
style: TextStyle(fontSize: 18)),
),
Divider(),
Text(
'Kundenanschrift: ',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w200),
),
SizedBox(
height: 8.0,
),
TextButton(
child: Text('${widget.post.data["Anschrift"]}'),
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return MapsDemo();
})),
),
SizedBox(
height: 8.0,
),
Divider(),
Text(
'Kommentar:',
style: TextStyle(fontWeight: FontWeight.w200, fontSize: 18.0),
),
SizedBox(
height: 16.0,
),
Text('${widget.post.data["Kommentar"]}',
style: GoogleFonts.lexendDeca()),
Divider(),
Text(
'Details der Anfrage: ',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w200),
),
SizedBox(
height: 16.0,
),
Text('Anfrage vom: ${widget.post.data["Anfrage vom"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text('Küchenlänge: ${widget.post.data["Küchenlaenge"]} Meter',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text('Hängeschränke: ${widget.post.data["Hängeschränke"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text(
'Gebrauchte Küche: ${widget.post.data["Gebrauchte Küche"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text(
'Arbeitsplatte schneiden: ${widget.post.data["Arbeitsplatte bearbeiten"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text(
'Anschluss Waschmaschine: ${widget.post.data["Anschluss WaMa"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text(
'Anschluss Spülmaschine: ${widget.post.data["Anschluss Spuel"]}',
style: GoogleFonts.lexendDeca()),
SizedBox(
height: 16.0,
),
Text(
'Anschluss Herd: ${widget.post.data["Anschluss Herd"]}',
style: GoogleFonts.lexendDeca(),
),
SizedBox(
height: 16.0,
),
Text(
'Wunschdatum Montage: ${widget.post.data["Wunschdatum"]}',
style: GoogleFonts.lexendDeca(),
),
SizedBox(
height: 16.0,
),
Text(
'Gesamt geschätzt: ${widget.post.data["Gesamt geschätzt"]} Euro',
style: GoogleFonts.lexendDeca(
fontSize: 18,
fontWeight: FontWeight.bold,
decoration: TextDecoration.underline),
),
TextField(
controller: adminComment,
decoration: InputDecoration(
hintText: 'Anmerkung Administrator:',
)),
//Kommentare von Administratoren:
Container(
child: Text(
'${widget.post.data['Administrator Anmerkung']}',
style: GoogleFonts.lexendDeca(),
)),
Column(
children: [
Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.red,
),
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (BuildContext context) {
return AlertDialog(
title: Text('Diese Anfrage wirklich löschen?',
style: GoogleFonts.lexendDeca()),
actions: [
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Abbrechen')),
TextButton(
onPressed: () async {
setState(() {
deleteDocument();
Navigator.push(context,
MaterialPageRoute(builder:
(BuildContext context) {
return Admins();
}));
});
},
child: Text('Löschen')),
],
);
}));
},
child: Text('Anfrage löschen')),
),
],
),
],
),
),
),
),
);
}
}
Related
On the add Weight screen I pick a weight and a date and then it gets stored in a list in the Hive database, once I press "Save".
It also returns me to the Homepage, where I would like to depict the stored list items in a ListView.Builder.
I only get the last item on the list and not the whole list.
When I am at the add weight screen, I see that there are more items in the list, but once I return to homepage only the last one exists.
AddWeightScreen
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:intl/intl.dart';
import 'package:weighty/components/my_alert_box.dart';
import 'package:weighty/data/database.dart';
import 'package:weighty/screens/home_page.dart';
class AddWeight extends StatefulWidget {
const AddWeight({super.key});
#override
State<AddWeight> createState() => _AddWeightState();
}
class _AddWeightState extends State<AddWeight> {
Database db = Database();
final _myBox = Hive.box("mybox");
double _currentValue = 0;
DateTime _dateTime = DateTime.now();
String formattedDate = DateFormat('d MMM yyyy').format(DateTime.now());
final _weightController = TextEditingController();
void _showDatePicker() {
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime.now(),
).then((value) {
setState(() {
_dateTime = value!;
formattedDate = DateFormat('d MMM yyyy').format(_dateTime);
});
});
}
// add weight from text - keyboard
void _dialogNumber() {
showDialog(
context: context,
builder: (context) {
return MyAlertBox(
controller: _weightController,
hintText: "Enter today's weight...",
onSave: () {
if (double.parse(_weightController.text) > 200) {
_weightController.text = "200";
}
setState(() {
_currentValue = double.parse(_weightController.text);
});
_weightController.clear();
Navigator.pop(context);
},
onCancel: cancelDialogBox);
});
}
//save method
void _saveWeightAndDate() {
setState(() {
db.weightList.add([_currentValue, formattedDate]);
});
db.saveData();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const HomePage(),
),
);
}
// cancel new weight input
void cancelDialogBox() {
// clear textfield
_weightController.clear();
// pop dialog box
Navigator.of(context).pop();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFD9F0FF),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
const SizedBox(
height: 28.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Add Weight",
style: TextStyle(fontSize: 36, fontWeight: FontWeight.w600),
),
MaterialButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text(
'CANCEL',
style: TextStyle(
color: Color(0xff878472),
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
),
),
],
),
const SizedBox(height: 30),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: MaterialButton(
onPressed: _dialogNumber,
child: Text(
_currentValue.toStringAsFixed(2) + " kg",
style: TextStyle(
color: Color(0xFF006B8F),
fontSize: 46,
fontWeight: FontWeight.w500),
),
),
),
const SizedBox(height: 30),
Slider(
value: _currentValue,
min: 0,
max: 200,
onChanged: ((value) {
setState(() {
_currentValue = value;
});
}),
),
const SizedBox(height: 30),
TextButton.icon(
onPressed: _showDatePicker,
icon: const Icon(
Icons.date_range_outlined,
size: 24.0,
color: Color(0xff878472),
),
label: Text(
formattedDate,
style: TextStyle(color: Color(0xff878472), fontSize: 18),
),
),
const SizedBox(height: 30),
ElevatedButton(
onPressed: _saveWeightAndDate,
child: Text(
'SAVE',
style:
TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
style: ElevatedButton.styleFrom(
elevation: 24,
padding:
EdgeInsets.symmetric(vertical: 20, horizontal: 80),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
side: BorderSide(color: Colors.white, width: 2),
),
),
),
const SizedBox(height: 30),
],
),
),
],
),
),
);
}
}
HomePage
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:weighty/components/weight_tile.dart';
import 'package:weighty/data/database.dart';
import 'package:weighty/main.dart';
import 'package:weighty/screens/add_weight.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
//First time ever opening app, Create default data
// if (_myBox.get("WEIGHTLIST") == null) {
// }
//already exists data
db.loadData();
// db.saveData();
super.initState();
}
Database db = Database();
final _myBox = Hive.box("mybox");
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[100],
floatingActionButton: FloatingActionButton(
backgroundColor: Color(0xff006B8F),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AddWeight(),
),
);
},
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 28),
Text(
"CURRENT",
style: TextStyle(
color: Colors.grey[500],
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
),
Text(
db.weightList.length == 0
? "00.0 Kg"
: db.weightList.last[0].toStringAsFixed(2) + " kg",
style: TextStyle(
color: Color(0xFF006B8F),
fontSize: 46.0,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 40),
Center(
child: Text(
"GRAPH",
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: ListView.builder(
itemCount: db.weightList.length,
itemBuilder: (context, index) {
return WeightTile(
date: db.weightList[index][1],
weight: db.weightList[index][0].toStringAsFixed(2),
);
},
),
),
ElevatedButton(
onPressed: () {
print(db.weightList.length);
},
child: Text('Print!')),
],
),
),
);
}
}
Hive Database
import 'package:hive_flutter/hive_flutter.dart';
class Database {
//reference the box
final _myBox = Hive.box("mybox");
// Empty Weight List
List weightList = [];
// void createInitialData() {
// weightList = [];
// }
//load the date from the db
void loadData() {
weightList = _myBox.get("WEIGHTLIST");
}
//save the weight
void saveData() {
_myBox.put("WEIGHTLIST", weightList);
}
}
I could not rebuild your project to debug it. so I'm kind of taking a shot in the darkness.
there is a widget called valuelistenablebuilder which gets rebuilt when ever a value changes you can set your box to the value being listened by this widget and rebuild every time a new value is added to your box you can find an example on this page
For whole list you have to first get old list which is saved in hive then sum this list and save in to hive
Output is
For you example you have to update saveData method in to a Database class
void saveData() {
final myBox = Hive.box("mybox");
List? hiveList = [];
hiveList = myBox.get("WEIGHTLIST") ?? [];
if (hiveList!.isNotEmpty) {
hiveList += weightList;
} else {
hiveList = weightList;
}
_myBox.put("WEIGHTLIST", hiveList);
}
You will be get whole list into a homescreen
I will describe my coding problem.
Well I have created Login/signUp .dart files(pages) but while debugging I got this error...
The method 'showSnackBar' isn`t defined for the type 'ScaffoldState'.
This error message appears everywhere in .dart code where I have this coding line...
`
scaffoldKey.currentState.showSnackBar(snackbar);
`
Here below is full code of my "login_page.dart" file...
`
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
void showSnackBar(String title) {
final snackbar = SnackBar(
content: Text(
title,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 15),
),
);
scaffoldKey.currentState.showSnackBar(snackbar);
}
var emailIdController = TextEditingController();
var passwordController = TextEditingController();
Widget _buildLogin() {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 30),
child: Column(
children: [
InputTextField(
controller: emailIdController,
label: 'Email-Id',
icon: Icon(Icons.email_outlined),
),
InputTextField(
controller: passwordController,
label: 'Password',
icon: Icon(Icons.lock),
),
SizedBox(
height: 50,
),
GestureDetector(
onTap: () async {
// network connectivity
var connectivityResult = await Connectivity().checkConnectivity();
if (connectivityResult != ConnectivityResult.mobile &&
connectivityResult != ConnectivityResult.wifi) {
showSnackBar('No Internet connectivity');
return;
}
if (!emailIdController.text.contains('#')) {
showSnackBar('Please provide a valid email address');
}
if (passwordController.text.length < 6) {
showSnackBar('Please provide a password of length more than 6');
}
BuildContext dialogContext;
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
dialogContext = context;
return ProgressDialog(
status: 'Logging you in...',
);
},
);
context
.read<AuthenticationService>()
.signIn(
email: emailIdController.text.trim(),
password: passwordController.text.trim(),
)
.then((value) => Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return HomePage();
}),
));
Navigator.pop(dialogContext);
},
child: CustomButton(
text: 'Login',
),
),
Text("\nDon't have any account?"),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return SignUpPage();
}),
);
},
child: Text(
'SignUp here',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
),
),
SizedBox(
height: 20,
),
],
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
body: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Padding(
padding: EdgeInsets.only(top: 130),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
'hopOn',
style: TextStyle(
fontSize: 60,
letterSpacing: 2,
fontWeight: FontWeight.bold,
fontFamily: 'MuseoModerno',
// color: Colors.white,
),
),
SizedBox(height: 80),
Padding(
padding: EdgeInsets.symmetric(horizontal: 30),
child: Column(
children: [
InputTextField(
controller: emailIdController,
label: 'Email-Id',
obscure: false,
icon: Icon(Icons.email_outlined),
),
InputTextField(
controller: passwordController,
label: 'Password',
obscure: true,
icon: Icon(Icons.lock),
),
SizedBox(
height: 30,
),
GestureDetector(
onTap: () async {
// network connectivity
var connectivityResult =
await Connectivity().checkConnectivity();
if (connectivityResult != ConnectivityResult.mobile &&
connectivityResult != ConnectivityResult.wifi) {
showSnackBar('No Internet connectivity');
return;
}
if (!emailIdController.text.contains('#')) {
showSnackBar(
'Please provide a valid email address');
}
if (passwordController.text.length < 6) {
showSnackBar(
'Please provide a password of length more than 6');
}
BuildContext dialogContext;
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
dialogContext = context;
return ProgressDialog(
status: 'Logging you in...',
);
},
);
context
.read<AuthenticationService>()
.signIn(
email: emailIdController.text.trim(),
password: passwordController.text.trim(),
)
.then((value) => Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return HomePage();
}),
));
Navigator.pop(dialogContext);
},
child: CustomButton(
text: 'Login',
),
),
SizedBox(
height: 20,
),
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return SignUpPage();
}),
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Don't have any account?\t",
style: TextStyle(fontSize: 10),
),
Text(
'SignUp here',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 12),
),
],
),
),
SizedBox(
height: 20,
),
],
),
),
],
),
),
),
),
);
}
}
`
The problem from whole code appears in this class...
`
void showSnackBar(String title) {
final snackbar = SnackBar(
content: Text(
title,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 15),
),
);
scaffoldKey.currentState.showSnackBar(snackbar); // <=== here is problem, this line have error message --> The method 'showSnackBar' isn`t defined for the type 'ScaffoldState'.
}
`
Any help is appreciated.
Thank you!
I would like to fix that "snackBar" error problem.
I tryed several hours to fix it by myself but without succees.
Flutter uses below method to display the snackbar as per flutter.dev
ScaffoldMessenger.of(context).showSnackBar(snackBar);
I found a solution idea that other user named "Rohan" gave to me.
I changed problematic code line...
scaffoldKey.currentState.showSnackBar(snackbar);
to first solution (which still didn't worked,, appeared error "Undefined name: 'snackbar'")...
ScaffoldMessenger.of(context).showSnackBar(snackBar);
Didn`t worked, but then I found a solution from previous sample solution. This is general and working Solution for my problem...
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: snackbar));
This solution will help you, if you found the same or similar issue with "showSnackBar".
I want to retrieve the new created document id and display the document data in a new page. How can i get the document id? When onPressed() the elevated button, I want to retrieve the document data based on its id.
How can I bring the document id from addDiagnose(_type, _symptomsResult) so that I can navigate it to another page.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DiagnosisPage(documentId: documentId),
)
);
This is my current code.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:multiselect_formfield/multiselect_formfield.dart';
import 'package:petbuddies/user/diagnosis/diagnose_history.dart';
import 'package:petbuddies/user/diagnosis/diagnosis.dart';
class CheckerPage extends StatefulWidget {
const CheckerPage({Key? key}) : super(key: key);
#override
_CheckerPageState createState() => _CheckerPageState();
}
class _CheckerPageState extends State<CheckerPage> {
//retrieve options
final _formKey = GlobalKey<FormState>();
void _petTypeDropDownItemSelected(String newValueSelected) {
setState(() {
petType = newValueSelected;
});
}
clearText(){
_symptoms?.clear();
}
#override
void initState(){
super.initState();
_symptoms = [];
_symptomsResult = [];
}
List? _symptoms;
late List<dynamic> _symptomsResult;
var petType;
var _type;
final Stream<QuerySnapshot> petTypeStream = FirebaseFirestore.instance.collection('pet type').orderBy('name').snapshots();
final Stream<QuerySnapshot> symptomsStream = FirebaseFirestore.instance.collection('symptoms').orderBy('name').snapshots();
DocumentReference diagnosis = FirebaseFirestore.instance.collection('diagnosis').doc();
//store the diagnosis result
User? user = FirebaseAuth.instance.currentUser;
Future<void> addDiagnose(_type, _symptomsResult) async {
String petChosen = this._type;
List symptomsChosen = this._symptomsResult.toList();
QuerySnapshot<Map<String, dynamic>> snapshot =
await FirebaseFirestore.instance.collection("disease")
.where('petType',isEqualTo: petChosen)
.where('symptoms',arrayContainsAny: symptomsChosen)
.get();
List<String> diseaseRef = snapshot.docs.map((e) => e.id).toList();
String createdby = user!.uid;
Timestamp date = Timestamp.now();
List possibleDisease = diseaseRef.toList();
final data = {
'created by': createdby,
'date': date,
'pet chosen': petChosen,
'symptoms chosen': symptomsChosen,
'possible disease': possibleDisease,
};
//set document data
return diagnosis
.set(data)
.then((value) => print('Diagnose Report Added'))
.catchError((error)=>print("Failed to add: $error")
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue[900],
title: const Text("Pet Symptoms Checker",
style: TextStyle(color: Colors.white),
),
),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 30),
child: ListView(
children: [
Align(
alignment: Alignment.bottomRight,
child: TextButton(
child: const Text(
'History',
style: TextStyle(fontSize: 18),
),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => const DiagnoseHistoryPage(),));
},
),
),
Container(
padding: const EdgeInsets.all(12.0),
decoration: BoxDecoration(
border: Border.all(width: 3, color: Colors.indigo,),
borderRadius: const BorderRadius.all(Radius.circular(30)),
),
child: Column(
children: [
StreamBuilder<QuerySnapshot>(
stream: petTypeStream,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(
child: CircularProgressIndicator(),
);
}
return Container(
padding: const EdgeInsets.only(bottom: 16.0),
child: Row(
children: <Widget>[
Expanded(
flex: 2,
child: Container(
padding: const EdgeInsets.fromLTRB(12.0, 10.0, 10.0, 10.0),
child: const Text(
"Pet Type",
style: TextStyle(fontSize: 20),
),
),
),
Expanded(
flex: 3,
child: Row(
children: [
const SizedBox(width: 30,),
DropdownButton(
value: petType,
onChanged: (valueSelectedByUser) {
_petTypeDropDownItemSelected(valueSelectedByUser.toString());
},
hint: const Text('Choose Pet Type',),
underline: Container(),
items: snapshot.data!.docs.map((DocumentSnapshot document) {
return DropdownMenuItem<String>(
value: document.get('name'),
child: Text(document.get('name')),
);
}).toList(),
),
],
),
),
],
),
);
}),
StreamBuilder(
stream: symptomsStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if(snapshot.hasError){
print('Something went wrong');
}
if(snapshot.connectionState == ConnectionState.waiting){
return const Center(
child: CircularProgressIndicator(),
);
}
final List symptomsList = [];
snapshot.data!.docs.map((DocumentSnapshot document){
Map a = document.data() as Map<String, dynamic>;
symptomsList.add(a['name']);
a['id'] = document.id;
}).toList();
return MultiSelectFormField(
autovalidate: AutovalidateMode.disabled,
chipBackGroundColor: Colors.blue[900],
chipLabelStyle: const TextStyle(fontWeight: FontWeight.bold, color: Colors.white),
dialogTextStyle: const TextStyle(fontWeight: FontWeight.bold),
checkBoxActiveColor: Colors.blue[900],
checkBoxCheckColor: Colors.white,
dialogShapeBorder: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12.0))),
title: const Text(
"Symptoms",
style: TextStyle(fontSize:20),
),
validator: (value) {
if (value == null || value.length == 0) {
return 'Please select one or more symptoms';
}
return null;
},
dataSource: [
for (String i in symptomsList) {'value' : i}
],
textField: 'value',
valueField: 'value',
okButtonLabel: 'OK',
cancelButtonLabel: 'CANCEL',
hintWidget: const Text('Please choose one or more symptoms'),
initialValue: _symptoms,
onSaved: (value) {
if (value == null) return;
setState(() {
_symptoms = value;
}
);
},
);
}
),
const SizedBox(height:50,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: () async{
if(_formKey.currentState!.validate()){
setState(() {
_type = petType.toString();
_symptomsResult = _symptoms!.toList();
addDiagnose(_type,_symptomsResult);
final documentId = diagnosis.id;
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DiagnosisPage(documentId: documentId),
)
);
clearText();
}
);
}
},
child: const Text(
'Diagnose',
style: TextStyle(fontSize: 18),
),
style: ElevatedButton.styleFrom(primary: Colors.blue[900]),
),
],
),
],
),
)
],
),
),
),
);
}
}
The task text in edit_todo_screen is not updated. I'm using the same code as in item_tasks, where I change the status of the task to move between "Done" and "Archived" - everything works well here. I tried to change only the status in edit_todo_screen, but it does not change, although the code is identical to the code in item_tasks. Perhaps the problem is that I'm not passing the parameters correctly to edit_todo_screen. I need to be able to change the status of the task and the text of the task itself in edit_todo_screen. Attached below is a screenshot of the error that occurs when clicking the button in edit_todo_screen
Tell me, please, what could be my mistake?
cubit_db
class AppCubit extends Cubit<AppStates> {
AppCubit() : super(AppInitialState());
static AppCubit get(context) => BlocProvider.of(context);
void updateDatabase(String status, int id) async {
database!.rawUpdate(
'UPDATE tasks SET status = ? WHERE id = ?', [status, id]).then((value) {
getDataBase(database);
emit(AppUpdateDatabaseState());
});
}
void createDatabase() {
openDatabase(
'todo.db',
version: 1,
onCreate: (database, version) {
database
.execute(
'CREATE TABLE tasks (id INTEGER PRIMARY KEY, title TEXT, status TEXT)')
.then((value) => print('Table Created'))
.catchError((error) {
print('Error When Creating Table ${error.toString()}');
});
},
onOpen: (database) {
getDataBase(database);
print('database opened');
},
).then((value) {
database = value;
emit(AppCreateDatabaseState());
});
}
inserToDatabase({required String title}) async {
await database!.transaction((txn) async {
txn
.rawInsert(
'INSERT INTO tasks (title, status) VALUES ("$title","New")')
.then((value) {
getDataBase(database);
print('$value Inserted Successfully');
emit(AppInsertDatabaseState());
}).catchError((error) {
print('Error When inserting Table ${error.toString()}');
});
});
}
new_tasks_list
class NewTasksScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BlocConsumer<AppCubit, AppStates>(
listener: (context, state) {},
builder: (context, state) {
var tasks = AppCubit.get(context).newTasks;
return SingleChildScrollView(
child: Column(children: [
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: tasks.length,
itemBuilder: (context, index) => TaskItem(tasks: tasks[index]),
),
]),
);
},
);
tasks_item
class TaskItem extends StatelessWidget {
Map? tasks;
TaskItem({this.tasks});
#override
Widget build(BuildContext context) {
return Card(
key: Key(tasks!['title']),
shadowColor: Colors.blueGrey,
margin: const EdgeInsets.only(left: 15, right: 15, top: 8),
color: Colors.black,
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.grey.shade800, width: 0.5),
borderRadius: BorderRadius.circular(10),
),
borderOnForeground: false,
child: ListTile(
title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(
// '${state.loadedUser[index].description}',
tasks!['title'],
style: const TextStyle(
fontSize: 21.0,
// fontWeight: FontWeight.bold,
),
),
// Text(
// tasks!['status'],
// style: const TextStyle(fontSize: 21.0),
// ),
]),
trailing: IconButton(
tooltip: 'Archive Todo',
highlightColor: Colors.red,
onPressed: () {
AppCubit.get(context).updateDatabase('Archive', tasks!['id']);
},
icon: const Icon(
Icons.archive,
color: Colors.white,
),
),
leading: IconButton(
tooltip: 'Done Todo',
highlightColor: Colors.green,
onPressed: () {
AppCubit.get(context).updateDatabase('Done', tasks!['id']);
},
icon: const Icon(
Icons.check,
color: Colors.white,
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => EditTodoScreen(
title: tasks!['title'],
id: tasks!['id'],
),
),
);
},
),
);
}
}
edit_todo_screen
class EditTodoScreen extends StatelessWidget {
// Map? tasks;
String title;
int id;
EditTodoScreen({Key? key, required this.title, required this.id})
: super(key: key);
final _controller = TextEditingController();
#override
Widget build(BuildContext context) {
_controller.text = title;
return BlocConsumer<AppCubit, AppStates>(
listener: (context, state) {},
builder: (context, state) {
return Scaffold(
appBar: AppBar(
title: const Text(
'Edit Todo',
style: TextStyle(fontSize: 20.0),
),
),
body: _body(context),
);
});
}
Widget _body(context) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
TextFormField(
controller: _controller,
autocorrect: true,
maxLines: 2,
decoration: const InputDecoration(hintText: 'Enter todo message'),
),
const SizedBox(
height: 10.0,
),
// ElevatedButton(
// // style:,
// onPressed: () {
// AppCubit.get(context).updateDatabase('Done', id);
// },
// child: Text(
// 'Update Data',
// style: TextStyle(color: Colors.amber.shade700),
// ),
// ),
InkWell(
onTap: () {
AppCubit.get(context).updateDatabase('Done', id);
Navigator.pop(context);
},
child: _updateBtn(context),
)
],
),
);
}
Widget _updateBtn(context) {
return Container(
width: MediaQuery.of(context).size.width,
height: 50.0,
decoration: BoxDecoration(
color: Colors.black, borderRadius: BorderRadius.circular(10.0)),
child: Center(
child: Text(
'Update Todo',
style: TextStyle(
fontSize: 17.0,
color: Colors.amber.shade700,
fontWeight: FontWeight.bold),
),
),
);
}
}
I think your problem has to do with the fact that database is not set in the second case. The code fails because you try to access a null value that then is checked with the "!" operator. Look where you set the database and check if that code is called in both code flows.
edit:
I think this line in edit todo screen is your problem: AppCubit.get(context).updateDatabase('Done', id);. If I am not mistaken AppCubit.get(context) returns null. The easiest way to check if I am right would be to replace it with the following:
final appCubit = AppCubit.get(context);
print('$appCubit');
appCubit.updateDatabase('Done', id);
If I am right, you should see "null" in your terminal.
What I think happens is, that the app cubit is not provided in the context anymore, because you pushed the todo screen as a new screen on the navigator. With that, the context that is provided is that of the navigator (or probably the material app in your case) which is above the point where you provide the AppCubit.
I am kind of guessing though, because I only see half of your code. I hope it helps nevertheless. :)
I am trying to use a list from a Cloud Firestore document field (called 'a_ge_vi') to populate my DropdownMenu options. This takes the form of an array of strings (see attached image).
However, when I try to produce the List<String> with data from Cloud Firestore and put it in the variable _partyList2, I get the error in the console of Undefined name '_partyList2'. I created a version of the list in Flutter and this works fine - it is shown as _partyList. But really I want to use the data from Cloud Firestore so I can change the values when I need to.
Can anyone help with why this isn't working?
PS. It is worth noting that this text widget Text(snapshot.data.documents[0]['q01'] does show q01, which is also a field in my Cloud Firestore document so I am connecting to the database.
I have the following code:
import 'package:flutter/material.dart';
import 'package:rewardpolling/pages/login_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
final responseInstance = Firestore.instance;
final _auth = FirebaseAuth.instance;
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
List<String> _partyList = <String>[
"Conservatives",
"Labour",
"Liberal Democrats",
"SNP",
"Plaid Cymru",
"The Brexit Party",
"Other",
"I would not vote"
];
class TestSurvey extends StatefulWidget {
static const String id = 'TestSurvey';
#override
_TestSurveyState createState() => _TestSurveyState();
}
class _TestSurveyState extends State<TestSurvey> {
var selectedParty, submittedParty, userid;
#override
void initState() async {
super.initState();
await Firestore.instance
.collection('MySurveys')
.document('FirestoreTestSurvey')
.get()
.then((DocumentSnapshot document) {
List<String> _partyList2 = document.data['a_ge_vi'];
print(_partyList2);
});
}
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xffEEEEEE),
appBar: AppBar(
backgroundColor: Color(0xff303841),
title: Center(child: Text('Test Survey')),
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pushNamed(context, LoginScreen.id);
}),
],
leading: Padding(padding: EdgeInsets.only(left: 12), child: Text(' ')),
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: FormBuilder(
key: _fbKey,
child: ListView(
children: <Widget>[
Padding(padding: EdgeInsets.all(16.0)),
StreamBuilder(
stream:
Firestore.instance.collection('MySurveys').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text('Loading data');
return Column(
children: <Widget>[
Text(
snapshot.data.documents[0]['q01'],
textAlign: TextAlign.left,
overflow: TextOverflow.visible,
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: "Roboto",
fontSize: 20),
),
DropdownButton(
items: _partyList2
.map((value) => DropdownMenuItem<dynamic>(
child: Text(
value,
style:
TextStyle(color: Color(0xff303841)),
),
value: value,
))
.toList(),
onChanged: (selectedParty) {
setState(() {
submittedParty = selectedParty;
});
},
value: submittedParty,
isExpanded: true,
hint: Text(
'Please choose an option',
style: TextStyle(color: Color(0xff303841)),
),
),
SizedBox(
width: double.infinity,
child: RaisedButton(
child: Text('Submit Survey'),
onPressed: () async {
final FirebaseUser user =
await _auth.currentUser();
final String userid = user.uid;
responseInstance
.collection("testSurvey08052020")
.add({
"user_id": userid,
"ge_vi": submittedParty,
"submission_time": DateTime.now()
});
})),
],
);
},
),
],
),
)),
);
}
}
I see that you have defined the List<String> _partyList2 = document.data['a_ge_vi']; in the initState.Its an issue of scope as the rest of code doesn't have access to the variable _partyList2;
What you can do is define the variable in the state and then assign it in initState
Hope this answers your question.
As mentioned by Shubham this issue is due to scope, as _partyList2 is only accessible in method initState the solution to this is add a variable that is accesible in other parts of the code and setting it to this value on initState.
I corrected the code and added below:
import 'package:flutter/material.dart';
import 'package:rewardpolling/pages/login_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
final responseInstance = Firestore.instance;
final _auth = FirebaseAuth.instance;
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
List<String> _partyList = <String>[
"Conservatives",
"Labour",
"Liberal Democrats",
"SNP",
"Plaid Cymru",
"The Brexit Party",
"Other",
"I would not vote"
];
class TestSurvey extends StatefulWidget {
static const String id = 'TestSurvey';
#override
_TestSurveyState createState() => _TestSurveyState();
}
class _TestSurveyState extends State<TestSurvey> {
var selectedParty, submittedParty, userid, usablePartyList;
#override
void initState() async {
super.initState();
await Firestore.instance
.collection('MySurveys')
.document('FirestoreTestSurvey')
.get()
.then((DocumentSnapshot document) {
List<String> _partyList2 = document.data['a_ge_vi'];
print(_partyList2);
usablePartyList = _partyList2;
});
}
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xffEEEEEE),
appBar: AppBar(
backgroundColor: Color(0xff303841),
title: Center(child: Text('Test Survey')),
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pushNamed(context, LoginScreen.id);
}),
],
leading: Padding(padding: EdgeInsets.only(left: 12), child: Text(' ')),
),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: FormBuilder(
key: _fbKey,
child: ListView(
children: <Widget>[
Padding(padding: EdgeInsets.all(16.0)),
StreamBuilder(
stream:
Firestore.instance.collection('MySurveys').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text('Loading data');
return Column(
children: <Widget>[
Text(
snapshot.data.documents[0]['q01'],
textAlign: TextAlign.left,
overflow: TextOverflow.visible,
style: TextStyle(
fontWeight: FontWeight.bold,
fontFamily: "Roboto",
fontSize: 20),
),
DropdownButton(
items: usablePartyList
.map((value) => DropdownMenuItem<dynamic>(
child: Text(
value,
style:
TextStyle(color: Color(0xff303841)),
),
value: value,
))
.toList(),
onChanged: (selectedParty) {
setState(() {
submittedParty = selectedParty;
});
},
value: submittedParty,
isExpanded: true,
hint: Text(
'Please choose an option',
style: TextStyle(color: Color(0xff303841)),
),
),
SizedBox(
width: double.infinity,
child: RaisedButton(
child: Text('Submit Survey'),
onPressed: () async {
final FirebaseUser user =
await _auth.currentUser();
final String userid = user.uid;
responseInstance
.collection("testSurvey08052020")
.add({
"user_id": userid,
"ge_vi": submittedParty,
"submission_time": DateTime.now()
});
})),
],
);
},
),
],
),
)),
);
}
}
flutter dart google-cloud-firestore