Creating Stream for StreamBuilder with Firestore - flutter

I'm have created a Stream that it working inside StreamBuilder, but I have to pass some parameters to my Stream, this parameters are in a dart file which only has functions. I'm attempting to create the same code that was working, but passing the user uid.
This is what I attempted:
Stream<QuerySnapshot> main_page_stream() async*{
final FirebaseUser user = await _auth.currentUser();
Stream stream = Firestore.instance.collection('user_data').
document(user.uid).collection('Buttons').snapshots();
await for(var event in stream) {
yield event.documents;
}
}
I get the following error:
Exception has occurred.
NoSuchMethodError (NoSuchMethodError: Class 'QuerySnapshot' has no instance getter 'snapshot'.
Receiver: Instance of 'QuerySnapshot'
Tried calling: snapshot)
This isn't working on the home page:
StreamBuilder(
stream: _auth.main_page_stream(),
builder: (context, snapshot) {
if (snapshot.hasError){
return Container(color: Colors.red);
}
if (!snapshot.hasData){
print(snapshot.data);
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasData){
var screenSize = MediaQuery.of(context).size.width;
return Stack(
children: [
this was working:
stream: Firestore.instance.collection('user_data').document('sdsajnd82173812').collection('Buttons').snapshots(),

The QuerySnapshot - event doesn't have a field snapshot. Instead you have to
yield event;
And for this the function return you the Stream<QuerySnapshot>.

Related

When I call the function in Text Widget, I get this display in my screen "instance of Future dynamic"?

This is the function, I want to retrieve currentUser data.
getData() async {
User? user = await FirebaseAuth.instance.currentUser;
print(user?.displayName);
}
How to display the name on the screen
When I call the function in text widget i.e
Text(getData().toString()),
I get the following display Instance of 'Future'<'dynamic'>''
i'm a beginner in Flutter, please help!
Since the function getData is async, it's a Future and you can't use a future methods inside your tree widget directly
you can use it inside your widget tree using the widget FutureBuilder
FutureBuilder(
future: getData(),
builder: (context, snapshot){
if (!snapshot.hasData) return const SizedBox();
return Text(snapshot.data?.toString() ?? '');
}
also, you have to modify your method to make it return something,
Ex.:
getData() async {
User? user = await FirebaseAuth.instance.currentUser;
print(user?.displayName);
return user?.displayName;
}
UPDATE:
to access all the info you want from the User object, let your method return the whole object;
getData() async {
User? user = await FirebaseAuth.instance.currentUser;
print(user?.displayName);
return user;
}
and your FutureBuilder will be
FutureBuilder(
future: getData(),
builder: (context, snapshot){
if (!snapshot.hasData) return const SizedBox();
if (snapshot.data == null) return const Text('Current user is null');
return Column(
children: [
Text('Name: ${snapshot.data?.displayName}'),
Text('Email: ${snapshot.data?.email}'),
///Add any attribute you want to show..
]
);
}
getData() async {
User? user = await FirebaseAuth.instance.currentUser;
if(user!=null){
print(user.displayName);
print(user.email);}
}
this will wait for an async method to first complete then print

Combine two stream-queries in flutter

I want to create a streambuilder to download multiple user-profiles from firebase. But to know which users are needed I have to get the user-ids at first, these are stored in an array. So I created a method to download the array and after this is done the streambuilder loads the user-data for each user-id from the array. Here's the code:
Method to get the array (executed in initState()):
Stream<QuerySnapshot> stream() async* {
job = Job.fromJson(await FirebaseFirestore.instance
.collection("jobs")
.doc(widget.jobId)
.get());
applicants = job.applicants;
await FirebaseFirestore.instance
.collection('users')
.where('uid', whereIn: applicants)
.snapshots();
}
And the streambuilder in the scaffolds' body:
body: isLoading
? Center(child: Container(child: CircularProgressIndicator()))
: applicants.isEmpty
? Center(
child: Text("no values"),
)
: StreamBuilder<QuerySnapshot>(
stream: stream(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else { xy }
So my question is if there's a possibility to combine the first method and the stream. Because at the moment the user can't get any update if an application is withdrawn while using the screen.

Firestore Class 'QuerySnapshot' has no instance method '[]'

I want a ListView to show the names of the users. I am using a cloudfunction with the admin sdk to return a list of all the users with the corresponding user IDs. When I want to pass that uid to a Widget with a streambuilder, it gives me the error:
Class 'QuerySnapshot' has no instance method '[]'.
Receiver: Instance of 'QuerySnapshot'
Tried calling: []("firstName")
This is the function I am calling while building the ListView for the title:
Widget getFirstName(uid, item) {
return StreamBuilder(
stream: Firestore.instance
.collection('users')
.document('HzBUMs06BAPHK0Y7m5kfOmUzawC2')
.collection('userInfo')
.snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Text('${item['email']}');
} else {
return Text('${snapshot.data.documents['firstName']}');
}
},
);
}
I am not using the uid which I will pass to it yet, as the User ID that I hardcoded right now is the only one with the firstName data in it.
When I feed it a non-existing userID, it still seems to think it has data in it and tries to return its (non-existent) data.
What am I doing wrong here?
I managed to fix it by using this piece of code:
Widget fullNameWidget(uid) {
return FutureBuilder(
future: fullName(uid),
builder: (context, snapshot) {
return Text('${snapshot.data}');
},
);
}
Future fullName(uid) async {
return Firestore.instance
.collection("users")
.document('$uid')
.collection("userInfo")
.getDocuments()
.then((querySnapshot) {
print(querySnapshot.documents[0]['firstName']);
if (querySnapshot == 'null') {
} else {
return '${querySnapshot.documents[0]['firstName']} ${querySnapshot.documents[0]['lastName']}';
}
// querySnapshot.documents.where((element) {
// print(element.documentID == 'firstName');
// });
});
}

Another exception was thrown: NoSuchMethodError: The method '[]' was called on null

var wfa_res = await CallApi().getData('waiting_for_approval/waiting_approval_list/'+widget.username+'/'+'0/requisition');
var wfa_res_body = json.decode(wfa_res.body);
in widget
for(var my_index = 0; my_index < wfa_res_body.length; my_index++)
Container(
padding: EdgeInsetsDirectional.fromSTEB(5,5,5,5),
// child: Text('design'),
child: Text(approvalInfo != null?approvalInfo['page_data'][my_index]['requisition_code']:''),
),
error
Another exception was thrown: NoSuchMethodError: The method '[]' was called on null.
Problem is that your widget is getting build before async method is completed.
Try using future builder e.g.
Your method :
Future yourMethodName() async {
var wfa_res = await CallApi().getData('waiting_for_approval/waiting_approval_list/'+widget.username+'/'+'0/requisition');
var wfa_res_body = json.decode(wfa_res.body);
return wfa_res_body;
}
Future Builder :
FutureBuilder(
future: yourMethodName(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Center(child: CircularProgressIndicator());
}
// after getting data from api
},
);
I fixed the problem. Actually the api response was too slow. right now i set a loader. and working fine. Thanks to all for answer.

Different type error when trying to access BLoC data in StreamBuilder

I'm trying to implementing Bloc on Flutter and i just learn about this feature and i get error:
Error:
Another exception was thrown: type 'Future' is not a subtype of type 'Stream'
my server return this structure and i want to get that with bloc and rxDart, for example:
[
"active"=> 1,
"name"=> "MY NAME",
"avatar"=> "http://www.sample.com/avatar.png",
...
]
my implemented Repository class :
class Repository {
final userInformation = InstagramApiProviders();
Future<UserInfo> userInfo() => userInformation.checkUserLogin();
}
LoginBlock class
class LoginBlock{
final _repository = Repository();
final _login_fetcher = PublishSubject<UserInfo>();
Observable<UserInfo> get login=>_login_fetcher.stream;
fetchLogin() async{
UserInfo userInfo = await _repository.userInfo();
_login_fetcher.sink.add(userInfo);
}
dispose(){
_login_fetcher.close();
}
}
final bloc = LoginBlock();
click on button on view implementation:
onPressed: () {
setState(() {
if (_checkLoginInstagram()) {
StreamBuilder(
stream: bloc.fetchLogin(),
builder: (context,
AsyncSnapshot<UserInfo>
snapshot) {
if (snapshot.hasData) {
parseResponse(snapshot);
}
},
);
}
});
},
parseResponse method:
void parseResponse(AsyncSnapshot<UserInfo> snapshot) {
debugPrint(snapshot.data.avatar);
}
You are providing a Future object instead a stream to stream property of your StreamBuilder.
//...
StreamBuilder(
stream: bloc.fetchLogin(), // THIS LINE IS WRONG
As your fetchLogin is an async function by default async methods returns always a Future object in your case Future<void>. You should replace the wrong line by:
//...
StreamBuilder(
stream: bloc.login,
And make fetchLogin() call in onPress callback and you don't need setState calls. I cant get it why you have a setState call there...