Below you can see a code where I want to display data that I have collected from a registration form in Flutter.
the registration form push the data to a collection called " user " then some other documents data are pushed as:
name - email etc...
As you can see by XXXX I want that the data I retrieve from cloud firestore be shown into the widget:
Below the code:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class WelcomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.pink,
body: MainWelcome(),
);
}
}
class MainWelcome extends StatefulWidget {
#override
_MainWelcomeState createState() => _MainWelcomeState();
}
class _MainWelcomeState extends State<MainWelcome> {
final databaseReference = Firestore.instance;
Future<QuerySnapshot> getData() async {
return await Firestore.instance.collection("user").getDocuments();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: getData(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
snapshot.data.documents.forEach((element) {
Center(
child: Text(
'Benvenuta ${element.data["name"]}',
style: TextStyle(fontSize: 20, color: Colors.white),
),
);
});
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return Center(child: CircularProgressIndicator());
},
);
}
}
You need to use a FutureBuilder widget to display the data in the widget tree:
Create a method that returns the data:
Future<QuerySnapshot> getData() async {
return await Firestore.instance
.collection("user")
.where("email", isEqualTo: "email_here")
.getDocuments();
}
Then inside the build() method do the following:
FutureBuilder(
future: getData(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
contentPadding: EdgeInsets.all(8.0),
title:
Text(snapshot.data.documents[index].data["name"]),
);
});
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return CircularProgressIndicator();
},
),
Related
I'm having trouble reading data from firestore. I want to display a user's name on screen after it is stored in firestore.
firestore document
my code is as follows, and thank you in advance for any assistance given:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
final db = FirebaseFirestore.instance.collection('users').snapshots();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test'),
),
body: StreamBuilder<QuerySnapshot>(
stream: db,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
} else
return ListView(
children: snapshot.data!.docs.map((doc) {
return Card(
child: ListTile(
title:
// Text(doc.data()['title']),
Text(doc.get('First name')
),
));
}).toList(),
);
},
),
final Stream<DocumentSnapshot<Map<String, dynamic>>> db = FirebaseFirestore.instance
.collection('users')
.doc('Personal details')
.snapshots();
...
body: StreamBuilder<DocumentSnapshot>(
stream: db,
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) return Text('Something went wrong');
if (snapshot.connectionState == ConnectionState.waiting)
return CircularProgressIndicator();
dynamic data = snapshot.data.data();
print(data);
print(data['First name']); // should print 'Guy'
print(data['Last name']); // should print 'Fang'
return Text(data['First name']);
},
),
In the code you showed, you are listening to the 'users' collection, instead, listen to the document 'Personal details' as shown above.
I load data from Cloud Firestore from Firebase. In the print statement in the function loadAssignments() the loaded data are showing correct. But when i will show the data in the Text widget with the widget FutureBuilder it doesn't show the data and i don't know why. Can anyone please help me?
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class AssignmentPage extends StatefulWidget {
#override
_AssignmentPageState createState() => _AssignmentPageState();
}
class _AssignmentPageState extends State<AssignmentPage> {
Future _loadAssignments;
QuerySnapshot _assignments;
#override
void initState() {
super.initState();
_loadAssignments = loadAssignments();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Bühlmaier App'),
centerTitle: true,
automaticallyImplyLeading: false,
),
body: FutureBuilder(
future: _loadAssignments,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
itemCount: _assignments.documents.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: Text('${_assignments.documents[index].data['Name'].toString()}'),
),
);
});
} else if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Center(child: CircularProgressIndicator());
},
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => toPage(NewAssignmentPage()),
),
);
}
Future<void> loadAssignments() async {
_assignments = await Firestore.instance.collection('assignments').getDocuments();
for (int i = 0; i < _assignments.documents.length; i++) {
print('DATEN: ' + _assignments.documents[i].data['Name'].toString());
}
setState(() {});
}
}
When i add the following code:
else if (snapshot.connectionState == ConnectionState.waiting) {
return Text("No data");
}
it works, but when i edit the code to:
else if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
}
it don't load the data and the CircularProgressIndicator() is not moving.
Use the method in the future property:
FutureBuilder(
future: loadAssignments(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: ListTile(
leading: Text('${snapshot.data.documents[index].data['Name'].toString()}'),
),
);
});
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return CircularProgressIndicator();
},
),
Change the method to the following:
Future<QuerySnapshot> loadAssignments() async {
return await Firestore.instance.collection('assignments').getDocuments();
}
This is a minimal reproducible code.
StreamController<DocumentSnapshot> _controller = StreamController.broadcast();
Stream<DocumentSnapshot> myStream = _controller.stream;
void main() {
WidgetsFlutterBinding.ensureInitialized();
_controller.addStream(Firestore.instance.document('user/data').snapshots());
runApp(MaterialApp(home: Page1()));
}
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.navigate_next),
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => Page2())),
),
body: Center(
child: StreamBuilder(
stream: myStream,
builder: (_, snapshot) {
if (snapshot.hasData) return Text('${snapshot.data}');
return CircularProgressIndicator();
},
),
),
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StreamBuilder(
stream: myStream,
builder: (_, snapshot) {
print("$snapshot");
if (snapshot.hasData) return Text('${snapshot.data}');
return CircularProgressIndicator();
},
),
),
);
}
}
When you run this code, 1st StreamBuilder displays data, but as you navigate to 2nd page, you'll see my 2nd StreamBuilder doesn't show any data, snapshot.data returns null. Can anyone help?
Edit: I have edited the post and now I am using StreamController.broadcast();
How would you implement a pull-down to refresh in Flutter app that gets data from a collection in Firestore preferable using a StreamBuilder or a FutureBuilder and displays it in a ListView ?
I ended up using information from here. How to refresh or reload a flutter firestore streambuilder manually?
I added the Refresh indicator and made the my stream get its data from a function see code below.
var stream;
#override
void initState() {
setState(() {
stream = mouvesStream();
});
super.initState();
}
Stream<QuerySnapshot> stream() {
return Firestore.instance.collection(_locationState).snapshots();
}
#override
Widget build(BuildContext context) {
body: StreamBuilder(
stream: stream,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Text(snapshot.error);
}
if (snapshot.connectionState == ConnectionState.active) {
List aList = new List();
aList.clear();
for (DocumentSnapshot _doc in snapshot.data.documents) {
Model _add = new Model.from(_doc);
aList.add(_add);
}
return TabBarView(
children: <Widget>[
RefreshIndicator(
onRefresh: _handleRefresh,
child: ListView.builder(
itemCount: aList.length,
itemBuilder: (context, index) {
return Card(aList[index]);
},
),
),
Icon(Icons.directions_transit),
],
);
} else {
return Container(
child: Center(child: CircularProgressIndicator()));
}
})));
}
This question already has answers here:
Flutter ListView Jumps To Top
(4 answers)
Closed 2 years ago.
Scrolling up from partway down the list makes the page jump to top. I'm using Flutter and Firestore, with a StreamBuilder to get the data.
I've tried changing scroll physics, setting placeholders, and it doesn't seem to help.
StreamBuilder<QuerySnapshot>(
// Create a stream listening to the posts collection
stream: widget.firestore
.collection('posts')
.orderBy('sequence', descending: false)
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
// When we don't have data yet (!...hasData), display the text "Loading..."
if (!snapshot.hasData) return const Text('Loading...');
final int messageCount = snapshot.data.documents.length;
// When data is availible, load
return new ListView.builder(
//padding: EdgeInsets.all(3.0),
itemCount: messageCount,
itemBuilder: (_, int index) {
final DocumentSnapshot document = snapshot.data.documents[index];
if (document["type"] == "standard")
return StandardCard(widget.firestore, document.documentID);
else if (document["type"] == "text")
return TextCard(widget.firestore, document.documentID);
else if (document["type"] == "video")
return VideoCard(widget.firestore, document.documentID);
else
return Card(
// Database is incorrect
child: Center(
child: Text("[Missing sufficient information]"),
),
);
},
);
},
),
It scrolls smoothly when you scroll down, but jerks to the top on an up-scroll.
Here's a self-contained example.
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'ListView Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'ListView Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
stream() async* {
yield ObjectHasFuture();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: StreamBuilder(
stream: stream(),
builder: (BuildContext context, snapshot) {
if (!snapshot.hasData) return const Text('Loading...');
return ListView.builder(
itemBuilder: (_, int index) {
return Card(
child: snapshot.data,
);
},
);
}));
}
}
class ObjectHasFuture extends StatelessWidget {
data() async {
await Future.delayed(Duration(seconds: Random().nextInt(2)));
return Container(
height: 250,
color: Colors.green,
child: Center(
child: Text(Random().nextInt(10000).toString()),
),
);
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: data(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text("Loading");
return snapshot.data;
});
}
}
Are you doing this in debug mode or release mode? Debug mode sometimes demonstrates odd artifacts that go away in the final build.
give it a scrollController:
Listview.builder(
controller: ScrollController(),
//
)
If you are dealing with static data of very low number of list items, you can speed the list up using
ListView(
addAutomaticKeepAlives: true,
...
)