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
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
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.
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');
// });
});
}
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.
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...