How can I get a subcollection on Firebase without specifying it? - firebase

Hey Guys I have these subcollections on my Firebase database under the "vocabulary" collection, but I would need to call them without specifying it, as they are more than one and they are called from the same page. Instead of the collection "colors", is it possible to not specify it as the "documentID" but for the collection?
class CategoryScreen extends StatelessWidget {
final DocumentSnapshot vocabulary;
CategoryScreen(this.vocabulary);
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<QuerySnapshot>(
future: Firestore.instance.collection('vocabulary').document(vocabulary.documentID)
.collection('colors').getDocuments(),
builder: (context, snapshot){
if(!snapshot.hasData)
return Center(
child: CircularProgressIndicator(),);
else
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: Card(
elevation: 7.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50)
),
child: Column(
children: <Widget>[
Container(
height: 350.0,
width: 350.0,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(vocabulary.data["image"]
),
fit: BoxFit.fill),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(50),
topRight: Radius.circular(50)))
),
Container(
height: 70.0,
width: 300.0,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: Center(
child: AutoSizeText(vocabulary.data["name"],
style: TextStyle(
fontFamily: 'Twiddlestix',
fontSize: 25,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
minFontSize: 15,
),
)
),
),
],
),
),
),
],
);
},
),
);
}
}

There are no wildcards in Cloud Firestore references to documents. So in order to create a query, you need to know all collection names. If you need to get only some documents within a collection based on a specific property, you'll have to do a query using some field value as a filter.
Instead of the collection "colors", is it possible to not specify it as the "documentID" but for the collection?
No, it's not possible. You cannot substitute that.

Related

Only first card return from StreamBuilder in Flutter run --release

I am creating flutter web app with Firebase realtime database. I just got different result for the release mode, there are only one Card widget return in release mode.
I am using "List items" as container and put the cards into that. Is't looks great in debug mode, but why only one card in the gridView after turned into release mode.
debug mode command: flutter run
release mode command: flutter run --release
Different between release mode and debug mode
Put my Scaffold class as following.
Scaffold(
appBar: AppBar(
title: Text('Sense'),
backgroundColor: Color.fromRGBO(133, 1, 132, 1),
),
body: StreamBuilder(
stream: databaseRef.onValue,
builder: (BuildContext context, AsyncSnapshot snap) {
if (!snap.hasError && snap.hasData) {
fb.DataSnapshot snapshot = snap.data.snapshot;
List<Widget> items = [];
snapshot.forEach((e) => items.add(Card(
color: Colors.grey[200],
elevation: 5,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 50,
padding: EdgeInsets.all(10),
// decoration: BoxDecoration(
// border: Border.all(color: Colors.red)),
child: FittedBox(
child: Text(
e.key.toUpperCase(),
style: TextStyle(
letterSpacing: 3,
fontWeight: FontWeight.bold),
),
),
),
Expanded(
child: Container(
padding: EdgeInsets.all(10),
// decoration: BoxDecoration(
// border: Border.all(color: Colors.green)),
child: FittedBox(
child: Text(
e.val().toString(),
style: TextStyle(
color: Color.fromRGBO(133, 1, 132, 1)),
)))),
Container(
padding: EdgeInsets.all(10),
height: 50,
// decoration: BoxDecoration(
// border: Border.all(color: Colors.blue)),
child: FittedBox(
child: Text(
'Unit: ',
style: TextStyle(color: Colors.grey),
),
),
),
],
),
)));
return GridView.extent(
maxCrossAxisExtent: 480,
padding: EdgeInsets.all(5),
children: items);
} else {
return SpinKitDoubleBounce(
color: Color.fromRGBO(133, 1, 132, 1));
}
},
),
bottomNavigationBar: BottomAppBar(
color: Colors.transparent,
elevation: 0,
child: SvgPicture.asset('logo.svg'),
)),
);
Your StreamBuilder need to specify the Object. And if it's a List just check List.isNotEmpty
StreamBuilder<List<Object>>(
stream: databaseRef.onValue,// need to return : Stream<List<Object>>
builder: (context, snap) {
if (!snap.hasError && snap.hasData) {
final items = snap.data;
if(items.isNotEmpty){
...
}
}
});
It can fix by the following method.
snapshot.forEach((e) => items.add(Card(...)))
to
snapshot.forEach((e) {items.add(Card(...))})
Does anyone know the root cause?

How can I use provider without context?

I have a widget where I use the provider but where I want to use the values is in normal widgets so maybe anyone can help.
This is where I use the provider :
Widget _buildName(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Full Name',
style: kLabelStyle3,
),
SizedBox(height: 10.0),
Container(
alignment: Alignment.centerLeft,
height: 50.0,
child: TextFormField(
initialValue: UserData.fullname;
validator: (val) => val.isEmpty ? 'Enter your Name' : null,
onChanged: (val) {
setState(() => _currentfullname = val);
},
style: TextStyle(
color: Colors.black,
fontFamily: 'OpenSans',
),
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
borderSide: BorderSide(
color: Colors.black,
width: 2.0,
),
),
contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(
Icons.person,
color: Colors.black,
),
hintText: 'Enter your Name',
hintStyle: kHintTextStyle2,
),
),
),
],
);
}
#override
Widget build(BuildContext context) {
final user = Provider.of<Userr>(context);
return StreamBuilder<UserData>(
stream: DatbaseService(uid:user.uid).userData,
builder: (context, snapshot) {
if(snapshot.hasData){
UserData userData =snapshot.data;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Form(
key: _formKey,
child: Stack(
children: <Widget>[
Container(
height: double.infinity,
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.symmetric(
horizontal: 40.0,
vertical: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Stack(
children: [
Container(
width: 110,
height: 110,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
"https://images.pexels.com/photos/3307758/pexels-photo-3307758.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=250",
))),
),
Positioned(
bottom: 0,
right: 0,
child: Container(
height: 35,
width: 35,
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
width: 4,
color: Theme.of(context)
.scaffoldBackgroundColor,
),
color: Colors.green,
),
child: Icon(
Icons.edit,
color: Colors.white,
),
)),
],
),
),
SizedBox(
height: 10,
),
Text(
'Mein Profil',
style: TextStyle(
color: Colors.black,
fontFamily: 'OpenSans',
fontSize: 20.0,
fontWeight: FontWeight.w600,
),
),
showAlert2(),
_buildEmailTF(),
SizedBox(
height: 30.0,
),
_buildName(),
SizedBox(
height: 30.0,
),
_builduserName(),
SizedBox(
height: 30.0,
),
_buildPasswordTF(),
SizedBox(height: 30,),
_buildPassword2TF(),
_buildUpdateDataButton(),
// _buildEmailform(),
],
),
),
)
],
),
),
),
),
);
}else{
return null;
}
}
);
}
}
class DatbaseService{
final String uid;
DatbaseService({this.uid});
//collection reference
final CollectionReference myprofilsettings = FirebaseFirestore.instance.collection('meinprofilsettings');
Future updateUserData(String user,String fullname,String password,String email)async{
return await myprofilsettings.doc(uid).set({
'username':user,
'fullname':fullname,
'passwort':password,
'email':email,
});
}
//profil list from snapshot
List<myprofil> _myprofillistFromSnapshot(QuerySnapshot snapshot){
return snapshot.docs.map((doc){
return myprofil(
user: doc.data()['user']??'',
fullname: doc.data()['fullname']??'',
email: doc.data()['email']??'',
passowrd: doc.data()['password']??'',
);
}).toList();
}
//userData from snapshot
UserData _userDataFromSnapshot(DocumentSnapshot snapshot){
return UserData(
uid: uid,
name: snapshot.data()['name'],
fullname: snapshot.data()['fullname'],
email: snapshot.data()['email'],
password: snapshot.data()['password'],
);
}
//get myprofilsettings stream
Stream<List<myprofil>> get settings{
return myprofilsettings.snapshots().map(_myprofillistFromSnapshot);
}
//get user doc stream
Stream<UserData> get userData{
return myprofilsettings.doc(uid).snapshots().map(_userDataFromSnapshot);
}
}
import 'package:flutter/cupertino.dart';
class Userr{
final String uid;
Userr({this.uid});
}
class UserData {
final String uid;
final String user;
final String fullname;
final String email;
final String passowrd;
UserData({this.uid,this.user,this.fullname,this.email,this.passowrd, name, password});
Ignore this:
Because flutter says __it looks like It looks like your post is mostly code; please add some more details. ___
IM adding some textdehpkfnwrfemrjfikerfoiwnfdoiwjefiojnweoidfjwiodjwiojdoijweiodjweiojdoiewjdijewoijdoejwdiojewiojdiowjedijweoidjiowediwjdoiwejdiowjdiojwoidjaldknjlncjnnc xy,,y,y,,y,ykampkdnndendiowendiojweiopjdipqejkdpojkdposkqwpodkqopwkdopkqwopdskqopdkpoqwkdopqkwopdkqwpodkpoqkdpkqpodkpqkdpokdpo<skcpoaskdpoakdopkdpoekwopdkwepokdpowekdpokwepodkwepokdpowekdpowekpdkpekdpokeopdkpekdpowekdopewkpdkwpekdpwekdpowekdpowekdpowekdpkwepodkwepodkpoekdpoewkdpoekdp
======== Exception caught by widgets library =======================================================
The following assertion was thrown building StreamBuilder<UserData>(dirty, state: _StreamBuilderBaseState<UserData, AsyncSnapshot<UserData>>#c612d):
A build function returned null.
The offending widget is: StreamBuilder<UserData>
Build functions must never return null.
To return an empty space that causes the building widget to fill available room, return "Container()". To return an empty space that takes as little room as possible, return "Container(width: 0.0, height: 0.0)".
The relevant error-causing widget was:
StreamBuilder<UserData> file:///Users/name/StudioProjects/project/lib/seitenleiste/meinacount.dart:356:16
When the exception was thrown, this was the stack:
#0 debugWidgetBuilderValue.<anonymous closure> (package:flutter/src/widgets/debug.dart:305:7)
#1 debugWidgetBuilderValue (package:flutter/src/widgets/debug.dart:326:4)
#2 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4592:7)
#3 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4759:11)
#4 Element.rebuild (package:flutter/src/widgets/framework.dart:4281:5)
...
====================================================================================================
I’m assuming that your _buildName() is a method of your widget and that you call it from you build method somewhere.
This means that you can pass either the context or the user into this method:
_buildName(BuildContext context) {} or _buildName(User user) {}
Try providing more of the code next time, specifically the parts where you call the method.
Edit after post update:
You need to have the user object in the buildName method so you cannot simply do UserData.fullname because UserData is a class not an instance.
So to get your data in the buildName you need to change it to:
_buildName(UserData userData) {
userData.fullname; // this now exists
}
And call is like: _buildName(userData)

how to fetch data from firestore array of a document with flutter?

this is my users collection in cloud fire store:
users collection
this is the function that gets users from users collection in firestore
Stream<QuerySnapshot> fetchUsersInSearch() {
return Firestore.instance.collection('users').snapshots();
}
i use this method
final emailResults = snapshot.data.documents
.where((u) => u['email'].contains(query));
in the following streamBuilder to fetch users by their email.
i have this streamBuilder to populate the data on screen
return StreamBuilder<QuerySnapshot>(
stream: DatabaseService().fetchUsersInSearch(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
final emailResults = snapshot.data.documents
.where((u) => u['email'].contains(query));
if (!snapshot.hasData) {
return Container(
color: Theme.of(context).primaryColor,
child: Center(
child: Text(
'',
style: TextStyle(
fontSize: 16, color: Theme.of(context).primaryColor),
),
),
);
}
if (emailResults.length > 0) {
return Container(
color: Theme.of(context).primaryColor,
child: ListView(
children: emailResults
.map<Widget>((u) => GestureDetector(
child: Padding(
padding: const EdgeInsets.all(0.1),
child: Container(
padding: EdgeInsets.symmetric(vertical: 5),
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
border: Border(
bottom: BorderSide(
width: 0.3, color: Colors.grey[50]))),
child: ListTile(
leading: CircleAvatar(
backgroundColor:
Theme.of(context).primaryColor,
backgroundImage:
NetworkImage(u['userAvatarUrl']),
radius: 20,
),
title: Container(
padding: EdgeInsets.only(left: 10),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(u['email'],
style: TextStyle(
fontSize: 16,
color: Theme.of(context)
.accentColor),
overflow: TextOverflow.ellipsis),
SizedBox(
height: 5,
),
],
),
),
),
),
),
onTap: () {
showUserProfile(u['id']);
},
))
.toList(),
),
);
} else {
return Container(
color: Theme.of(context).primaryColor,
child: Center(
child: Text(
'No results found',
style: TextStyle(
fontSize: 16,
color: Theme.of(context).accentColor,
),
),
),
);
}
});
this is working perfectly and fetching users inside a listView by their email...
p.s: the (query) is a string i type in a seach bar.
how can i make a query to fetch users by their otherUsernames...the second field in the screenshot of the users collection ?!
i tried this:
final otherUsernamesResults = snapshot.data.documents
.where((u) => u['otherUsernames'].contains(query));
but its returning this error:
The method 'contains' was called on null.
Receiver: null
Tried calling: contains("#username1")
what am i doing wrong here ?!!
any help would be much appreciated..
Try this:-
Stream<QuerySnapshot> getUsers() {
final usersCollection = FirebaseFirestore.instance.collection('users');
return usersCollection.where('otherUsernames', arrayContainsAny: ['username1', 'username2']);
}
For firestore version 0.16.0

Fetch user data from firestore and show them in profile screen using flutter

The issue here is that when I fetch the data, I am suppose to fetch it for the current user but it is rather fetching data for all users within that collection.
I have done reading and watched a number of videos for a possible solution but I can't seem to find how to do this. Your help is needed please. Thanks.
A excerpt of the bode is below.
File image;
TextEditingController loginNameController = TextEditingController();
TextEditingController loginPhoneController = TextEditingController();
TextEditingController loginAddressController = TextEditingController();
clearForm() {
setState(() {
image = null;
loginNameController.clear();
loginPhoneController.clear();
loginAddressController.clear();
});
}
//=====> FOR INSTANCES OF FIREBASE <=====
final auth = FirebaseAuth.instance;
final db = FirebaseFirestore.instance;
User user = FirebaseAuth.instance.currentUser;
body: Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: StreamBuilder(
stream: db.collection("collection name").snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot){
if (!snapshot.hasData) {
return Center(
child: spinkit,
);
}
return ListView.builder (
itemCount: snapshot.data.docs.length,
itemBuilder: (BuildContext context, int index){
return Stack(
children: [
Column(
children: [
Stack(
children: [
// ===> RETRIEVING USER DETAILS AND SHOWING IT IN A ROW <===
Container(
padding : EdgeInsets.only(top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CircleAvatar(
backgroundColor: Palette.mainColor,
radius: 50,
child: ClipOval(
child: SizedBox(
height: 150,
width: 150,
child: image == null ? Center(
// child: Image.asset("asset/images/placeholder.png", fit: BoxFit.cover,),
child: Image.network(snapshot.data.documents[index].get("image")),
):
Image.file(image, fit: BoxFit.cover,),
),
),
),
SizedBox(width: 16,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 0),
child: Text(snapshot.data.documents[index].get("Name"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),),
),
SizedBox(height: 5,),
Text(snapshot.data.documents[index].get("Address"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black54,
fontSize: 16,
),),
SizedBox(height: 5,),
Text(snapshot.data.documents[index].get("Number"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black54,
fontSize: 16,
),),
],
),
),
Padding(
padding: EdgeInsets.only(left: 0, bottom: 15),
child: IconButton(
icon:Icon(Icons.edit, color: Palette.mainColor, ),
onPressed: () { },
),
),
],
),
),
],
),
],
),
],
);
},
);
},
),
)
The collection name is members
Try like this, stream of your widget should be like this, as said above.
db.collection("Users").document(user.uid).snapshots();
for length in Listview.builder, change it too
snapshot.data.length;
And last, All the data which you fetch data like this should change into
from:
snapshot.data.documents[index].get("image")
To:
snapshot.data["image"]
Note I didn't test it. So, it might or might not work.
First of All use a DocumentSnapshot Shown below:
StreamBuilder<DocumentSnapshot>
Make a collection to get current user Profile data.
db.collection("Users").doc(user.uid).snapshots();
Remove ListView.builder
To get an Email Address use the below Line
Text('${streamSnapshot.data['Email Address']}'),
Here is the complete Article https://medium.com/#kamranktk807/fetch-user-data-from-firestore-and-show-them-in-profile-screen-using-flutter-609d2533e703
By the way I sol this problem with the help of a Professional Flutter Developer SHAKIR ZAHID [shakirzahid191#gmail.com].

Extract latitude and longitude from Firebase GeoPoint

Working in Flutter I can access sections of my database like so:
Streambuilder(
stream: Firestore.instance.collection('stores').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return CircularProgressIndicator();
return ListView.builder(
itemExtent: 60,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_buildListRows(context, snapshot.data.documents[index]),
);
}
),
And then the _buildListRows widget:
Widget _buildListRows(BuildContext context, DocumentSnapshot document) {
geoPoint = document.reference.firestore.
return Container(
height: MediaQuery.of(context).size.height * 0.7,
child: ListView(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Text(
'Business Name',
style: Theme
.of(context)
.textTheme
.headline,
),
),
Container(
decoration: const BoxDecoration(
color: Colors.teal,
),
padding: const EdgeInsets.all(10),
child: Text(
document['store_name'],
style: Theme
.of(context)
.textTheme
.display1,
),
),
],
),
Row(
children: <Widget>[
Expanded(
child: Text(
'Location',
style: Theme
.of(context)
.textTheme
.headline,
),
),
Container(
decoration: const BoxDecoration(
color: Colors.teal,
),
padding: const EdgeInsets.all(10),
child: Text(
document['location'].toString(),
style: Theme
.of(context)
.textTheme
.display1,
),
),
],
),
],
),
);
}
I am just getting started on this so looking at the best way to retrieve data on demand from the database and displaying it in the app. I just can't find anywhere that explains how to extract the longitude and latitude from the GeoPoint reference returned by: document['location'].toString(),
What I get from this output is:
Instance of 'GeoPoint'
Also, am I doing this right? Is this the best way to extract specific data from the database? It feels like I am doing this very inefficiently, but can't find another way to do this.
To access the longitude and latitude, then do the following:
child: Text(
document['location'].latitude.toString(),
style: Theme
.of(context)
.textTheme
.display1,
),
Since document['location'] returns an instance of GeoPoint, then just call the property latitude to get the value.

Resources