get firebase data without streambuilder - flutter

This is how I get data using stream builder from firebase
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('profile').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if (!snapshot.hasData) return const Text('Loading...');
final int messageCount = snapshot.data.documents.length;
return ListView.builder(
shrinkWrap: true,
itemCount: messageCount,
itemBuilder: (_, int index) {
final DocumentSnapshot document = snapshot.data.documents[index];
return Container();}
);
},
),
My question is, How to get a collection list data to a list inside initstate() maybe using a function
List data=new List();
#override
void initState() {
super.initState();
//here
}

Just do as follow inside your stateful class to fetch the data,
bool isFetching=false;
List<String> dataList=[];
#override
void initState() {
super.initState();
getGroupsData();
}
getGroupsData() {
setState(() {
isFetching= true;
});
databaseReference
.collection("profile")
.getDocuments()
.then((QuerySnapshot snapshot) {
snapshot.documents.forEach((f) => dataList.add[f.data["name"]));
setState(() {
isFetching= false;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child : isFetching ?
CircularProgressIndictaor()
: dataList!=null && dataList.length >0
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Text(dataList[index]);
}
)
: Text("No Data"),
)
);
}

Related

Flutter replace static List with Firebase Query

can anybody show me how to replace the static list (_dataFromQuerySnapShot) with Firestore Firebase QuerySnapshot? Thank you!
`
import 'dart:async';
import 'package:flutter/material.dart';
class SearchWidget extends StatelessWidget {
const SearchWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
const TextField(onChanged: _filter),
StreamBuilder<List<User>>(
stream: _stream,
builder: (context, snapshot) {
return StreamBuilder<List<User>>(
key: ValueKey(snapshot.data),
initialData: snapshot.data,
stream: _stream,
builder: (context, snapshot) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data?.length,
itemBuilder: (BuildContext context, int index) {
final data = snapshot.data?[index]?.name;
return Text(data!);
},
);
},
);
},
)
],
),
);
}
}
StreamController<List<MyUser>> _streamController = StreamController<List<MyUser>>();
Stream<List<MyUser>> get _stream => _streamController.stream;
_filter(String searchQuery) async {
List<MyUser> _dataFromQuerySnapShot = await getData();
List<MyUser> _filteredList = _dataFromQuerySnapShot.where((MyUser user) => user.firstName!.toLowerCase().contains(searchQuery.toLowerCase())).toList();
_streamController.sink.add(_filteredList);
}
Future<List<MyUser>> getData() async {
List<MyUser> dataList = [];
CollectionReference myRef = FirebaseFirestore.instance.collection('users');
QuerySnapshot querySnapshot = await myRef.get();
dataList.addAll(querySnapshot.docs.map((d) => MyUser.fromJson(d.data() as Map<String, dynamic>)));
return dataList;
}
`
I tried to get data by Future<List> getData() {...} but List _filteredList = getData(); doesn't work as well as a lot of other tries. I only need to see a simple solution of my example working with firebase (StreamController a.s.o.) please. The best solution will include instead of searching in name searching in a String of 'firstName', 'lastName', and 'nickName'...

Correct way to load ListView data source initially

I have a stateful widget whose state builds a ListView. The ListView gets its data from an http API. I am using a Future<void> method called getData to retrieve this data and populate a List<> with it before calling setState.
My question is where should I call getData when this screen first launches? If I call it in initState(), I get the following error in the debug console:
[VERBOSE-2:ui_dart_state.cc(198)] Unhandled Exception: dependOnInheritedWidgetOfExactType<_InheritedTheme>() or dependOnInheritedElement() was called before _EventListState.initState() completed.
If I wrap the call to getData in a delayed Future, I do not see the error. Here's my code:
class _EventListState extends State<EventList> {
Future<void> getData() async {
events = [];
events = await Network.getUsers(context);
setState(() {});
}
List<Event> events = [];
#override
initState() {
super.initState();
getData(); // this cause the error
// Future.delayed(Duration(seconds: 1), getData); // this works
}
#override
build(context) {
return PlatformScaffold(
iosContentPadding: true,
body: ListView.builder(
padding: const EdgeInsets.all(10),
physics: const AlwaysScrollableScrollPhysics(),
itemCount: events.length,
itemBuilder: (context, index) => Text(events[index].summary),
),
);
}
}
Forcing a delay to retrieve the data does not feel right, so is there a better way?
Use FutureBuilder.
List<Event> events = [];
#override
Widget build(BuildContext context) {
return FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return PlatformScaffold(
iosContentPadding: true,
body: ListView.builder(
padding: const EdgeInsets.all(10),
physics: const AlwaysScrollableScrollPhysics(),
itemCount: events.length,
itemBuilder: (context, index) => Text(events[index].summary),
),
);
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else {
return Center(child: Text('Please wait its loading...'));
}
},
future: getData(),
);
}
Future<void> getData() async {
events = [];
events = await Network.getUsers(context);
}

Future.wait returning null

class AdView extends StatefulWidget {
const AdView({Key? key, required String id}) : super(key: key);
final id = '2';
#override
_AdViewState createState() => _AdViewState();
}
class _AdViewState extends State<AdView> {
final _adService = NewsService();
Future<AdBanner?> futureAdd() async {
_adService.getAds('2');
}
Future<Categories?> futureCatergoriess() async {
_adService.getAllCategories();
}
#override
void initState() {
futureAdd();
futureCatergoriess();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Colors.grey[200],
body: FutureBuilder(
future: Future.wait([futureCatergoriess(), futureAdd()]),
builder: (context, AsyncSnapshot<List<dynamic>> snapshot) {
if (snapshot.hasData) {
final advertisements = snapshot.data![0];
return ListView.builder(
itemCount: advertisements!.length,
itemBuilder: (BuildContext context, int index) {
//return bannerListTile(advertisements, index, context);
return const Text('index');
});
} else {
if (snapshot.hasError) {
return NewsError(
errorMessage: '${snapshot.hasError}',
);
}
return const NewsLoading(
text: 'Loading...',
);
}
},
),
);
}
}
snapshot.data![0]; returning null value. I tried already many versions ([1] or snapshot.data.data but I cannot call the results.
I am using future.wait first time. There is no problem if I use any of API with traditional Future.builder.
any help?
after the advice of #ChristopherMoore I modified the code but the main problem is still continue. This code gives as output:
index
index
modified code
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: Future.wait([futureCatergoriess(), futureAdd()]),
builder: (context, AsyncSnapshot<List<dynamic>> snapshot) {
if (snapshot.hasData) {
final advertisements = snapshot.data!;
return ListView.builder(
itemCount: advertisements.length,
itemBuilder: (BuildContext context, int index) {
//return bannerListTile(advertisements, index, context);
return const Text('index');
});
This original line gives this error:
final advertisements = snapshot.data![0];
The getter 'length' was called on null. Receiver: null Tried calling: length The relevant error-causing widget was FutureBuilder<List<Object?>> lib/view/ad_view.dart:37

Flutter : Class 'Future<List<String>>' has no instance getter 'length'

I have a List of String saved on SharedPreference in Flutter app, I want to call it inside Provider and using it in a widget.
Provider :
get myTeam => getMyTeam();
Future<List<String>> getMyTeam() async {
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
final SharedPreferences prefs = await _prefs;
return prefs.getStringList('team');
}
I used it in future builder :
Widget build(BuildContext context) {
return Consumer<GeneralProvider>(
builder: (context, generalProvider, child) {
var items = generalProvider.myTeam;
return FutureBuilder(
future: items,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text('${items[index].club}'),
);
});
} else {
return Text('bad');
}
});
});
}
I get error : Class 'Future<List<String>>' has no instance getter 'length'
I tied with many solutions in questions here like :
Class 'Future<dynamic>' has no instance getter 'length'
but it wasn't solved
Change itemCount: items.length into itemCount: snapshot.length,
And Future builder to FutureBuilder<List<String>(...etc).
Will look like this in the end:
Widget build(BuildContext context) {
return Consumer<GeneralProvider>(
builder: (context, generalProvider, child) {
var items = generalProvider.myTeam;
return FutureBuilder<List<String>>(
future: items,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index) {
return ListTile(
// title: Text('${items[index].club}'),//This will likely throw an error also, because items is a List<String>, there is no method called "club" for Lists.
//Replace it with this to validate:
title: Text(snapshot[index]),//This
);
});
} else {
return Text('bad');
}
});
});
}

Can't retrieve a number of document into firestore flutter

I have a small problem, I need to retrieve into my list a collection retrieved by StreamBuilder from Firestore.
I am using snapshot.data.documents.lenght but once I add it I got error:
Class 'DocumentSnapshot' has no instance getter 'documents'.
Receiver: Instance of 'DocumentSnapshot'
Tried calling: documents
this is my code:
Stream<DocumentSnapshot> getDatabase() async* {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
yield* Firestore.instance
.collection('dataCollection')
.document(user.uid)
.snapshots();
}
#override
Widget build(BuildContext context,) {
return StreamBuilder(
stream: getDatabase(),
builder: (context, snapshot,) {
if (snapshot.data != null) {
return Column(
children: <Widget>[
Container(
height: 500,
child: ListView.builder(
shrinkWrap: true,
itemCount: 2,
itemBuilder: (BuildContext context, int index) {
return Card(
color: Color(0xFF1f2032),
elevation: 15,
child: Text(
snapshot.data['phone']..
just change your code as following
Stream dataStream
then
#override
void initState() {
getDatabase().then((value) {
dataStream = value;
setState(() {});
});
super.initState();
}
the funcion getDatbase()
getDatabase() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
yield* Firestore.instance
.collection('dataCollection')
.document(user.uid)
.snapshots();
}
then
#override
Widget build(BuildContext context,) {
return StreamBuilder(
stream: dataStream,
builder: (context, snapshot,) {
if (snapshot.data != null) {
return Column(
children: <Widget>[
Container(
height: 500,
child: ListView.builder(
shrinkWrap: true,
itemCount: 2,
itemBuilder: (BuildContext context, int index) {
return Card(
color: Color(0xFF1f2032),
elevation: 15,
child: Text(
snapshot.data['phone']..
Try this,
StreamBuilder(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<List<DocumentSnapshot>> snapshots) {
if (snapshots.connectionState == ConnectionState.active &&
snapshots.hasData) {
return Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshots.data.length,
itemBuilder: (BuildContext context, int index) {
//do something with snapshot.
}
}
return Container();
},
),
);
} else {
return Container();
}
},
),
Initialise your stream like this,
Stream<DocumentSnapshot> stream;
Future<dynamic> getDatabase() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
setState(() {
stream=Firestore.instance
.collection('dataCollection')
.document(user.uid)
.snapshots();
});
}
You can call getDatabase() in initState.
Update:-
This is your full code.
class DataCo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.blue,
),
body: Column(
children: [
CollectData(),
],
),
);
}
}
class CollectData extends StatefulWidget {
#override
_CollectDataState createState() => _CollectDataState();
}
class _CollectDataState extends State<CollectData> {
final String phone;
final String wife;
final String location;
_CollectDataState({this.phone, this.wife, this.location});
#override
void initState() {
super.initState();
getDatabase();
}
Stream<DocumentSnapshot> stream;
Future<dynamic> getDatabase() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
setState(() {
stream=Firestore.instance
.collection('dataCollection')
.document(user.uid)
.snapshots();
});
}
#override
Widget build(BuildContext context,) {
return StreamBuilder(
stream: stream,
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshots) {
if (snapshots.connectionState == ConnectionState.active &&
snapshots.hasData) {
return Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshots.data.length,
itemBuilder: (BuildContext context, int index) {
//do something with snapshot.
}
}
return Container();
},
),
);
} else {
return Container();
}
},
);
}
}
class NoData extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: [
Text('No Data available'),
],
);
}
}