Flutter Firebase Collection Sorting...认为我只有一步之遥
Flutter Firebase Collection Sorting... Think I'm Only A Step Away
更新
所以行 'final CollectionReference golfCartCollection = FirebaseFirestore.instance.collection('golf_cart');'工作并传递数据但是,如果我将 'CollectionReference' 更改为 'Query',它会在代码中进一步分解 '// 将新产品保存到 Firestore // await golfCartCollection.add({' with .add error要求提取方法和“//更新产品//等待golfCartCollection.doc(documentSnapshot!.id)”,并出现 .doc 错误要求提取方法。
结束更新
好的。我正在“自学”扑朔迷离,已经走到这一步了。按照教程、示例等,我现在可以通过 ListViews 显示信息,但是使用示例并将它们组合起来存在问题。我无法对 ListView 进行排序。
如果我将“CollectionReference”更改为“查询”,正如许多人指出的那样,我将失去功能并进一步出错。
请检查代码,如果可能的话,请将我推向正确的道路。一如既往,我感谢您提供的所有帮助。
顺便说一句,这是在 iOS 和 Android 模拟器上使用 VSCode 的 Flutter with Firebase。我将附上 ListView 屏幕的屏幕截图。
const GolfCartdbScreen({Key? key}) : super(key: key);
@override
_GolfCartdbScreenState createState() => _GolfCartdbScreenState();
}
class _GolfCartdbScreenState extends State<GolfCartdbScreen> {
static final DateTime now = DateTime.now();
// // YES there are many text controllers. Its a registration for golf carts and need this info. Will add the remaining controllers when I get it working // //
final _date = TextEditingController(text: '$now');
late bool _active;
final addCityController = TextEditingController(text: 'Welaka');
final addStateController = TextEditingController(text: 'FL');
final TextEditingController addStreetController = new TextEditingController();
final addZipController = TextEditingController(text: '32193');
final TextEditingController businessNameController =
new TextEditingController();
final TextEditingController dateInitialController =
new TextEditingController();
final TextEditingController dateRenewController = new TextEditingController();
final TextEditingController emailController = new TextEditingController();
final TextEditingController firstNameController = new TextEditingController();
final TextEditingController lastNameController = new TextEditingController();
final TextEditingController phoneNumberController =
new TextEditingController();
final TextEditingController regNumberController = new TextEditingController();
final TextEditingController timeStampController = new TextEditingController();
final TextEditingController vehColorController = new TextEditingController();
final TextEditingController vehMakeController = new TextEditingController();
final TextEditingController vehModelController = new TextEditingController();
final TextEditingController vinNumberController = new
// // // THE TWO LINES BELOW WORK TO PROVIDE THE DATA HOWEVER IF I CHANGE TO QUERY HAVE ISSUE FURTHER DOWN WITH 'await golfCartCollection.add' AND ' await golfCartCollection.doc(documentSnapshot!.id)' WITH ADD and DOC HAVING ERRORS // // //
final CollectionReference golfCartCollection =
FirebaseFirestore.instance.collection('golf_cart');
// This function is triggered when the floating button or one of the edit buttons is pressed
// Adding a product if no documentSnapshot is passed
// If documentSnapshot != null then update an existing product
Future<void> _createOrUpdate([DocumentSnapshot? documentSnapshot]) async {
String action = 'create';
if (documentSnapshot != null) {
action = 'update';
addStreetController.text = documentSnapshot['addStreet'].toString();
firstNameController.text = documentSnapshot['firstName'].toString();
lastNameController.text = documentSnapshot['lastName'].toString();
}
await showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext ctx) {
return Padding(
padding: EdgeInsets.only(
top: 20,
left: 20,
right: 20,
bottom: MediaQuery.of(ctx).viewInsets.bottom + 20),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: firstNameController,
decoration: const InputDecoration(labelText: 'Fisrt Name'),
),
TextField(
controller: lastNameController,
decoration: const InputDecoration(
labelText: 'Last Name',
),
),
TextField(
controller: addStreetController,
decoration: const InputDecoration(
labelText: 'Address: Street',
),
),
const SizedBox(
height: 20,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: CustomColors.welakaoneBlack,
),
child: Text(action == 'create' ? 'Create' : 'Update'),
onPressed: () async {
final String? firstName = firstNameController.text;
final String? lastName = lastNameController.text;
final String? addStreet = addStreetController.text;
if (firstName != null &&
lastName != null &&
addStreet != null) {
if (action == 'create') {
// Persist a new product to Firestore
await golfCartCollection.add({
"firstName": firstName,
"lastName": lastName,
"addStreet": addStreet
});
}
if (action == 'update') {
// Update the product
await golfCartCollection
.doc(documentSnapshot!.id)
.update({
"firstName": firstName,
"lastName": lastName,
"addStreet": addStreet
});
}
// Clear the text fields
firstNameController.text = '';
lastNameController.text = '';
addStreetController.text = '';
// Hide the bottom sheet
Navigator.of(context).pop();
}
},
)
],
),
);
});
}
// Deleteing a product by id
Future<void> _deleteProduct(String productId) async {
await golfCartCollection.doc(productId).delete();
// Show a snackbar
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('You Have Successfully Deleted The Registration.'),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
systemOverlayStyle: SystemUiOverlayStyle.dark,
backgroundColor: CustomColors.welakaoneBlack,
title: AppBarTitle(),
leading: Builder(
builder: (context) {
return IconButton(
onPressed: () {
Scaffold.of(context).openDrawer();
},
icon: Icon(Icons.menu),
);
},
),
actions: <Widget>[
Builder(
builder: (context) {
return IconButton(
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
icon: Icon(Icons.person),
);
},
),
],
),
drawer: new MyDrawer(),
endDrawer: new MyEndDrawer(
uid: '',
),
// Using StreamBuilder to display all products from Firestore in real-time
body: new Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
CustomColors.welakaoneBlack,
CustomColors.welakaoneBlueDark,
],
begin: FractionalOffset(0.0, 0.0),
end: FractionalOffset(1.6, 1.0),
stops: [0.3, 1.0],
tileMode: TileMode.clamp,
),
),
child: StreamBuilder(
stream: golfCartCollection.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
if (streamSnapshot.hasData) {
return ListView.builder(
itemCount: streamSnapshot.data!.docs.length,
itemBuilder: (context, index) {
final DocumentSnapshot documentSnapshot =
streamSnapshot.data!.docs[index];
return Card(
color: Colors.transparent,
margin: const EdgeInsets.all(0),
child: ListTile(
title: Text(
documentSnapshot['firstName'].toString() +
' ' +
documentSnapshot['lastName'.toString()],
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: CustomColors.welakaoneWhite,
),
),
subtitle: Text(
documentSnapshot['addStreet'].toString(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
color: CustomColors.welakaoneWhite,
),
),
trailing: SizedBox(
width: 100,
child: Row(
children: [
// Press this button to edit a single product
IconButton(
icon: const Icon(Icons.edit),
color: CustomColors.welakaoneYellow,
onPressed: () =>
_createOrUpdate(documentSnapshot)),
// This icon button is used to delete a single product
IconButton(
icon: const Icon(Icons.delete),
color: CustomColors.welakaoneYellow,
onPressed: () =>
_deleteProduct(documentSnapshot.id)),
],
),
),
),
);
},
);
}
return const Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
CustomColors.welakaoneYellow,
),
),
);
},
),
),
// Add new product
floatingActionButton: FloatingActionButton(
backgroundColor: CustomColors.welakaoneYellow,
onPressed: () => _createOrUpdate(),
child: const Icon(
Icons.add,
color: CustomColors.welakaoneBlueDark,
),
),
);
}
}
[![enter image description here][1]][1] ```
[1]: https://i.stack.imgur.com/5STK5.jpg
要对列表视图进行排序,请在此处添加一个 order-by 子句:
...
child: StreamBuilder(
stream: golfCartCollection.orderBy('lastName').snapshots(),
...
更新 所以行 'final CollectionReference golfCartCollection = FirebaseFirestore.instance.collection('golf_cart');'工作并传递数据但是,如果我将 'CollectionReference' 更改为 'Query',它会在代码中进一步分解 '// 将新产品保存到 Firestore // await golfCartCollection.add({' with .add error要求提取方法和“//更新产品//等待golfCartCollection.doc(documentSnapshot!.id)”,并出现 .doc 错误要求提取方法。 结束更新
好的。我正在“自学”扑朔迷离,已经走到这一步了。按照教程、示例等,我现在可以通过 ListViews 显示信息,但是使用示例并将它们组合起来存在问题。我无法对 ListView 进行排序。
如果我将“CollectionReference”更改为“查询”,正如许多人指出的那样,我将失去功能并进一步出错。
请检查代码,如果可能的话,请将我推向正确的道路。一如既往,我感谢您提供的所有帮助。
顺便说一句,这是在 iOS 和 Android 模拟器上使用 VSCode 的 Flutter with Firebase。我将附上 ListView 屏幕的屏幕截图。
const GolfCartdbScreen({Key? key}) : super(key: key);
@override
_GolfCartdbScreenState createState() => _GolfCartdbScreenState();
}
class _GolfCartdbScreenState extends State<GolfCartdbScreen> {
static final DateTime now = DateTime.now();
// // YES there are many text controllers. Its a registration for golf carts and need this info. Will add the remaining controllers when I get it working // //
final _date = TextEditingController(text: '$now');
late bool _active;
final addCityController = TextEditingController(text: 'Welaka');
final addStateController = TextEditingController(text: 'FL');
final TextEditingController addStreetController = new TextEditingController();
final addZipController = TextEditingController(text: '32193');
final TextEditingController businessNameController =
new TextEditingController();
final TextEditingController dateInitialController =
new TextEditingController();
final TextEditingController dateRenewController = new TextEditingController();
final TextEditingController emailController = new TextEditingController();
final TextEditingController firstNameController = new TextEditingController();
final TextEditingController lastNameController = new TextEditingController();
final TextEditingController phoneNumberController =
new TextEditingController();
final TextEditingController regNumberController = new TextEditingController();
final TextEditingController timeStampController = new TextEditingController();
final TextEditingController vehColorController = new TextEditingController();
final TextEditingController vehMakeController = new TextEditingController();
final TextEditingController vehModelController = new TextEditingController();
final TextEditingController vinNumberController = new
// // // THE TWO LINES BELOW WORK TO PROVIDE THE DATA HOWEVER IF I CHANGE TO QUERY HAVE ISSUE FURTHER DOWN WITH 'await golfCartCollection.add' AND ' await golfCartCollection.doc(documentSnapshot!.id)' WITH ADD and DOC HAVING ERRORS // // //
final CollectionReference golfCartCollection =
FirebaseFirestore.instance.collection('golf_cart');
// This function is triggered when the floating button or one of the edit buttons is pressed
// Adding a product if no documentSnapshot is passed
// If documentSnapshot != null then update an existing product
Future<void> _createOrUpdate([DocumentSnapshot? documentSnapshot]) async {
String action = 'create';
if (documentSnapshot != null) {
action = 'update';
addStreetController.text = documentSnapshot['addStreet'].toString();
firstNameController.text = documentSnapshot['firstName'].toString();
lastNameController.text = documentSnapshot['lastName'].toString();
}
await showModalBottomSheet(
isScrollControlled: true,
context: context,
builder: (BuildContext ctx) {
return Padding(
padding: EdgeInsets.only(
top: 20,
left: 20,
right: 20,
bottom: MediaQuery.of(ctx).viewInsets.bottom + 20),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextField(
controller: firstNameController,
decoration: const InputDecoration(labelText: 'Fisrt Name'),
),
TextField(
controller: lastNameController,
decoration: const InputDecoration(
labelText: 'Last Name',
),
),
TextField(
controller: addStreetController,
decoration: const InputDecoration(
labelText: 'Address: Street',
),
),
const SizedBox(
height: 20,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: CustomColors.welakaoneBlack,
),
child: Text(action == 'create' ? 'Create' : 'Update'),
onPressed: () async {
final String? firstName = firstNameController.text;
final String? lastName = lastNameController.text;
final String? addStreet = addStreetController.text;
if (firstName != null &&
lastName != null &&
addStreet != null) {
if (action == 'create') {
// Persist a new product to Firestore
await golfCartCollection.add({
"firstName": firstName,
"lastName": lastName,
"addStreet": addStreet
});
}
if (action == 'update') {
// Update the product
await golfCartCollection
.doc(documentSnapshot!.id)
.update({
"firstName": firstName,
"lastName": lastName,
"addStreet": addStreet
});
}
// Clear the text fields
firstNameController.text = '';
lastNameController.text = '';
addStreetController.text = '';
// Hide the bottom sheet
Navigator.of(context).pop();
}
},
)
],
),
);
});
}
// Deleteing a product by id
Future<void> _deleteProduct(String productId) async {
await golfCartCollection.doc(productId).delete();
// Show a snackbar
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('You Have Successfully Deleted The Registration.'),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
systemOverlayStyle: SystemUiOverlayStyle.dark,
backgroundColor: CustomColors.welakaoneBlack,
title: AppBarTitle(),
leading: Builder(
builder: (context) {
return IconButton(
onPressed: () {
Scaffold.of(context).openDrawer();
},
icon: Icon(Icons.menu),
);
},
),
actions: <Widget>[
Builder(
builder: (context) {
return IconButton(
onPressed: () {
Scaffold.of(context).openEndDrawer();
},
icon: Icon(Icons.person),
);
},
),
],
),
drawer: new MyDrawer(),
endDrawer: new MyEndDrawer(
uid: '',
),
// Using StreamBuilder to display all products from Firestore in real-time
body: new Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [
CustomColors.welakaoneBlack,
CustomColors.welakaoneBlueDark,
],
begin: FractionalOffset(0.0, 0.0),
end: FractionalOffset(1.6, 1.0),
stops: [0.3, 1.0],
tileMode: TileMode.clamp,
),
),
child: StreamBuilder(
stream: golfCartCollection.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> streamSnapshot) {
if (streamSnapshot.hasData) {
return ListView.builder(
itemCount: streamSnapshot.data!.docs.length,
itemBuilder: (context, index) {
final DocumentSnapshot documentSnapshot =
streamSnapshot.data!.docs[index];
return Card(
color: Colors.transparent,
margin: const EdgeInsets.all(0),
child: ListTile(
title: Text(
documentSnapshot['firstName'].toString() +
' ' +
documentSnapshot['lastName'.toString()],
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: CustomColors.welakaoneWhite,
),
),
subtitle: Text(
documentSnapshot['addStreet'].toString(),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
color: CustomColors.welakaoneWhite,
),
),
trailing: SizedBox(
width: 100,
child: Row(
children: [
// Press this button to edit a single product
IconButton(
icon: const Icon(Icons.edit),
color: CustomColors.welakaoneYellow,
onPressed: () =>
_createOrUpdate(documentSnapshot)),
// This icon button is used to delete a single product
IconButton(
icon: const Icon(Icons.delete),
color: CustomColors.welakaoneYellow,
onPressed: () =>
_deleteProduct(documentSnapshot.id)),
],
),
),
),
);
},
);
}
return const Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
CustomColors.welakaoneYellow,
),
),
);
},
),
),
// Add new product
floatingActionButton: FloatingActionButton(
backgroundColor: CustomColors.welakaoneYellow,
onPressed: () => _createOrUpdate(),
child: const Icon(
Icons.add,
color: CustomColors.welakaoneBlueDark,
),
),
);
}
}
[![enter image description here][1]][1] ```
[1]: https://i.stack.imgur.com/5STK5.jpg
要对列表视图进行排序,请在此处添加一个 order-by 子句:
...
child: StreamBuilder(
stream: golfCartCollection.orderBy('lastName').snapshots(),
...