How to display the data from firebase in flutter? - firebase

I am able to retrieve data from Firebase in flutter, but I do not know how to display them in my application as a list. Also, I do not know where to write my codes, do I have to write them in init state method or some where else?
I am able only to print the values in the debug console, not in the app. Please find the following codes that I am using to retrieve data from firebase and print them in debug console. These codes are written in the main.dart inside the initState method.
final retrieve = FirebaseDatabase.instance.reference().child("Transaction");
String _titleController;
String _amountController;
String _selectedDate;
String _selectedpicker;
#override
void initState() {
retrieve.once().then(
(DataSnapshot snapshot) {
Map<dynamic, dynamic> values = snapshot.value;
//for loop
values.forEach(
(key, value) {
print("OOoooooo");
print(value['title']);
final strem =
Firestore.instance.collection('Transaction').snapshots(),
_titleController = value['title'];
_amountController = value['amount'];
_selectedDate = value['Picker'];
_selectedpicker = value['Date'];
return StreamBuilder(
stream: stream,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text("Loading");
} else {
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot mytransaction =
snapshot.data.documents[index];
return Card(
elevation: 5,
margin: EdgeInsets.symmetric(
vertical: 8, horizontal: 5),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.purple,
radius: 30,
child: Padding(
padding: EdgeInsets.all(6),
child: FittedBox(
child: Text(
'\$${mytransaction['amount']}',
style: TextStyle(
color: Colors.white,
fontFamily: 'FjallaOne'),
),
),
),
),
title: Text(
'${mytransaction['title']}' +
" " +
'${mytransaction['Picker']}',
style: TextStyle(
color: Colors.black,
fontFamily: 'FjallaOne'),
),
subtitle: Text(
'${mytransaction['Date']}',
),
));
});
}
});
},
);
},
);
}

You need a list view builder or grid view builder or any builder depending on how you want to show your data.
Example:
return ListView.builder
(itemCount: litems.length,
itemBuilder: (BuildContext ctxt, int index) {
return new Text(value['title]);
}
)
You can return a column or something else to display all your data

Related

how to listen to a change in a stream from firebase

I am getting data from this stream builder and showing it inside a stateful widget.
Widget chatRoomsLists() {
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('chatrooms').orderBy("lastMessageSendTs", descending: true)
.where("users", arrayContains:myUserName)
.snapshots(),
builder: (context, snapshot){
return snapshot.hasData ? ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context,index){
DocumentSnapshot ds = snapshot.data!.docs[index];
return ChatRoomListTile(ds['lastMessage'], ds.id,myUserName! );
}) : Center(child: CircularProgressIndicator());
}) ;
}
and showing it here
class ChatRoomListTile extends StatefulWidget {
final String lastMessage , chatRoomId, myUsername;
ChatRoomListTile(this.lastMessage, this.chatRoomId, this.myUsername,);
#override
_ChatRoomListTileState createState() => _ChatRoomListTileState();
}
class _ChatRoomListTileState extends State<ChatRoomListTile> {
String profilePicUrl = 'https://miro.medium.com/max/875/0*H3jZONKqRuAAeHnG.jpg' , name = '' ,username = "";
getThisUserInfo() async {
print('userinfo called');
username = widget.chatRoomId.replaceAll(widget.myUsername, "").replaceAll("_", "");
QuerySnapshot querySnapshot = await DatabaseMethods().getUserInfo(username);
// print("something bla bla ${querySnapshot.docs[0].id} ${querySnapshot.docs[0]["name"]} ${querySnapshot.docs[0]["profileURL"]}");
name = "${querySnapshot.docs[0]["name"]}";
profilePicUrl = "${querySnapshot.docs[0]["profileURL"]}";
setState(() {});
}
#override
void initState() {
getThisUserInfo();
super.initState();
}
#override
Widget build(BuildContext context) {
print('BUILDING IS CALLED');
return GestureDetector(
onTap: () {
print('name is $username and ${widget.myUsername}');
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Chatting(username, widget.myUsername)));
},
child: Column(
children: [
Container(
margin: EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(30),
child: Image.network(profilePicUrl,
height: 40,
width: 40,
),
),
SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
style: TextStyle(fontSize: 16),
),
SizedBox(height: 3),
SizedBox(width: 220,
child: Text(widget.lastMessage,overflow: TextOverflow.ellipsis)),
],
)
],
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Divider(thickness: 0.5 ,),
)
],
),
);
}
}
I want to call get this future getThisUserInfo every time there is change in widget.lastmessage . How can i do that ?
When i am calling this future inside the build , It is getting called again and again non stop .So how can i only call this when there is a new message only ?
I would suggest you to review the construction of your builder and check the snapshot().listen() method, you can refer to this similar issue for that.
To your follow-up question, it is hard to say what is causing this duplicated update, as it can be a number of things and nothing in your code indicates that, so that being said, I would think of some logic that allows you to check if the update you want to make already happened, perhaps spending a read, which is less expensive than a write.

How can i fetch single value from Firebase real time database using a method

This is my method i intend to use it to fetch data from database to a Text widget
getSnapshotData (String child){
final User _firebaseUser = firebaseAuth.currentUser;
databaseReference
.child("users")
.child(_firebaseUser.uid)
.once()
.then((DataSnapshot dataSnapshot) {
return dataSnapshot.value('${child}');
}
);
this is my Text widget to retrieve name from the database
Text(
'Hi,' + ' ${getSnapshotData('name')}',
style: TextStyle(
color: Colors.black,
fontSize: 32,
)),
this is my Text widget to retrieve order count from the database
Text(
getSnapshotData('orders_count').toString(),
style: TextStyle(
color: Colors.black,
fontSize: 32,
)),
i have tried logging the values of orders count and name and virtually everything,
Everything seems to be ok i dont understand whats the problem i used more than three hours trying to look for a solution but failed
Use Future Builder to fetch data
create getPost() method first to return qn
Future getPosts() async {
var firestore = Firestore.instance;
QuerySnapshot qn = await firestore.collection("your_collecttion_name").getDocuments();
return qn.documents;
}
after that use, future builder to fetch data
return Container(
child: FutureBuilder(
future: getPosts(),
builder: (_, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Text("Loading..."),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return Column(
children: <Widget>[
Text(
snapshot.data[index].data['your_data']
.toString(),
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500),
),]
),}
),
});

How to get it from userUid() to the StreamBuilder Flutter

i was wondering how can i pass my function userUid() to the StreamBuilder {
FirebaseAuth auth = FirebaseAuth.instance;
userUid() async {
final FirebaseUser user = await auth.currentUser;
final uid = user.uid;
return uid;
}
Where I want to pass it, to get the document base on the logged user UID.
final tabs = [
final documentId = await userUid();
Center(
child: (Scaffold(
body: StreamBuilder (
stream: FirebaseFirestore.instance.collection('users').document(userUid()).snapshots(),
builder: (context, snapshot) {
if (snapshot.data == null) return CircularProgressIndicator();
return Container(
padding: EdgeInsets.all(16),
child: ListView.builder(
When I Pass the function final documentId = await useruid();inside the final tabs =[
I get the error
error: Expected an identifier. (missing_identifier at lib/pages/home.dart:39)
error: Expected to find ']'. (expected_token at lib/pages/home.dart:39)
idk what I can do to pass this function...
with someone know a document of example so i can study how to do it,
full code:
final tabs = [
final documentId = await userUid();
Center(
child: (Scaffold(
body: StreamBuilder (
stream: FirebaseFirestore.instance.collection('users').document(userUid()).snapshots(),
builder: (context, snapshot) {
if (snapshot.data == null) return CircularProgressIndicator();
return Container(
padding: EdgeInsets.all(16),
child: ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot manuais =
snapshot.data.documents[index];
return Card(
color: Colors.grey[250],
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Image.asset('Images/pdflogo.png', width: 32,
),
Center(
child: Text(
(manuais.data()['nome'].toString()),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 16),
),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('Compartilhar / Download'),
onPressed: () async {
var request = await HttpClient().getUrl(Uri.parse(manuais.data()['documento']));
var response = await request.close();Uint8List bytes = await consolidateHttpClientResponseBytes(response);
await Share.file(
'ESYS AMLOG',
'Manual.pdf',
bytes,
'image/jpg');
}),
],
),
],
),
),
);
}),
);
})))),
Center(
child: (Scaffold(
body: StreamBuilder(
stream: FirebaseFirestore.instance.collection('producao').snapshots(),
builder: (context, snapshot) {
if (snapshot.data == null) return CircularProgressIndicator();
return Container(
padding: EdgeInsets.all(16),
child: ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot producao =
snapshot.data.documents[index];
return Card(
color: Colors.grey[250],
child: Container(
padding: EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Image.network(producao.data()['img'].toString(), width: 260,
),
),
Text(
(producao.data()['data'].toString()),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 22),
),
Text(
(producao.data()['detail'].toString()),
style: TextStyle(fontSize: 16),
),
ButtonBar(
children: <Widget>[
FlatButton(
child: const Text('DETALHES'),
onPressed: () {
ImageViewer.showImageSlider(
images: [
(producao.data()['img']),
//List of images' URLs
],
);
}),
FlatButton(
child: const Text('COMPARTILHAR'),
onPressed: () async {
var request = await HttpClient().getUrl(Uri.parse(producao.data()['img']));
var response = await request.close();Uint8List bytes = await consolidateHttpClientResponseBytes(response);
await Share.file(
'ESYS AMLOG',
'amlog.jpg',
bytes,
'image/jpg'
);
}),
],
),
],
),
),
);
}),
);
})))),
Center(child: Text('Documentos')),
]; //<<<<<<<<<<<<<<< here closes the tab
````
You cannot define a variable inside a List. You could do two things:
Declare the documentId before the List instantiation:
final documentId = await userUid();
final tabs = [
...
];
Create a function that returns a list:
/// ... simulates the parameters of the function
List<Widget> getWidgetList(...) async {
final documentId = await userUid();
final List<Widget> list = [];
// To insert in a final list use the method add(...)
...
// Do your logic here
...
return list;
}
final tabs = getWidgetList(...);

Flutter: Unable to read data from firebase. The method '[]' was called on null error

I am trying to read the data from firebase after scanning a barcode.
This is how it should appear, but instead of barcode, it should display name and price from the database
(https://m.imgur.com/gallery/lEFJZ0Q)
Code:
class ListTileModel {
String barcode;
ListTileModel(this.barcode);
}
the below code is inside the stateful widget
List<ListTileModel> _items = [];
String barcode = "";
void _add() {
_items.add(ListTileModel(barcode));
setState(() {});
}
#override
void initState(){
super.initState();
}
StreamBuiler Used:
new Container(
child: ListView(
children: _items
.map((item) => StreamBuilder(
stream: FirebaseDatabase.instance.reference().child('prd').child(item.barcode).onValue,
builder: (context, snap) {
print(item.barcode);
if(snap.hasData){
DataSnapshot snapshot = snap.data.snapshot;
Map<dynamic, dynamic> itm = snapshot.value;
return snap.data.snapshot.value == null
? SizedBox()
: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: 1,
itemBuilder: (context, index) {
return Row(
children: <Widget>[
ConstrainedBox(
child: Container(
child: Text(itm[index]['name'],style: TextStyle(fontSize: 20),),
),
),
SizedBox(width: 100,),
ConstrainedBox(
child: Container(
child: Text(itm[index]['price'].toString(),style: TextStyle(fontSize: 20),),
),
),
],
);
},
);
}
else {
return Center(child: CircularProgressIndicator());
}
}
),
).toList()
),
),
The Barcode Scan code:
widget:
floatingActionButton: FloatingActionButton(
onPressed: scan,
child: Icon(Icons.add_shopping_cart),
),
scan() :
Future scan() async{
try{
String barcode = await BarcodeScanner.scan();
setState(() {
this.barcode = barcode;
});
_add();
}on PlatformException catch(e) {
if(e.code == BarcodeScanner.CameraAccessDenied){
setState(() {
this.barcode = 'Access Denied';
});
}
}
I'm am getting following Error:
The following NoSuchMethodError was thrown building:
The method '[]' was called on null.
Receiver: null
Tried calling:
Please try this and let me know if it fixes your problem you need to change
Text(itm[index]['name'],style: TextStyle(fontSize: 20),),
Text(itm[index]['price'].toString(),style: TextStyle(fontSize: 20),),
To
Text(itm['det']['name'],style: TextStyle(fontSize: 20),),
Text(itm['det']['price'].toString(),style: TextStyle(fontSize: 20),),
Let me know if this works for you. I believe the problem is the index also.
right now your saying.

Cant get StreamBuilder to display data from cloud firestore

I know I have a connection to the database and no errors are appearing so I'm pretty confused. The title and code should summarize the problem fairly well. Think I'm missing something?
here is the main code that should be displaying cards with titles from firebase
mainList() {
StreamBuilder(
stream: Firestore.instance.collection('Events').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text('Loading');
} else {
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) {
DocumentSnapshot userPost = snapshot.data.documents[index];
return Container(
width: MediaQuery.of(context).size.width,
height: 350.0,
child: Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Material(
elevation: 14.0,
shadowColor: Color(0x802196F3),
child: Center(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: 200.0,
child: Text(
'${userPost['title']}',
))
],
),
),
))),
);
},
);
}
});
}
and here is where the function is called:
lass MyAppmain extends State<MyApp> {
#override
Widget build(BuildContext context) {
var listView = ListView.builder(
itemCount: local.length,
itemBuilder: (BuildContext cnxt, int index) {
return new Text(local[index]);
});
return MaterialApp(
home: PageView(
controller: controller,
children: <Widget>[
//home page---------------------------
Scaffold(
appBar: AppBar(
title: Text(
'Events',
),
elevation: 20,
),
//main list view for the cards
//think I use streambuilder for this so google before starting
body: mainList(),//RIGHT HERE
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(context, NewEventTransition());
},
mini: true,
),
),
//Profile Page-------------------------------
Scaffold(
appBar: AppBar(
title: Text(
'Profile',
),
elevation: 20,
),
),
],
));
}
}
Want a listview of cards holding the titles from firebase (will soon be more than titles but want to get this working first)
This is a common problem.
return ListView.builder(
itemCount: snapshot.data.documents.length, // this line is the culprit!
itemBuilder: (context, index) {
print(snapshot.data.documents.length); // it will print null
.......
}
See, It takes some time to fetch data from firebase. When ListView.builder is called the value of snapshot.data.documents.length is actually null. Tho after few seconds it gets data but till then ListView had built the UI and that's why it's blank. To check the value, you can add a Print statement like shown above.
Now there are few ways to solve this problem:
Make an int variable say totalLength, make a function say setTotalLength which makes a call to Firebase/Firestore database and use setState to assign this value to totalLength and then change that code to this:
itemCount: totalLength,
You should Call setTotalLength in your initState method.
Or, you can change your code to this, But I'm NOT 100% sure that this will work:
itemCount: snapshot.data.documents.length ?? 0 // returns 0 if the value is null, may reload UI again when data comes

Resources