I am having trouble with this future builder and can not seem to find the solution. I'm trying to create a List of documents("posts) mapped to a custom class I created("BlogPosts") but when attempting to use it I get the following error.
error:
LateInitializationError: Field 'posts' has not been initialized.
the stack trace tells me the error is happening inside the builder but I have already initialized 'posts' in the future
future builder:
late User user;
late Userdata userdata;
CollectionReference usersRef = FirebaseFirestore.instance.collection('users');
CollectionReference postsRef = FirebaseFirestore.instance.collection('posts');
late List<BlogPost> posts;
FutureBuilder(
future: Future.wait([
usersRef.doc(user.uid).get().then((doc) {
userdata = Userdata.fromDocument(doc);
}),
postsRef.get().then((val) {
posts = val.docs.map((doc) => BlogPost.fromDocument(doc)).toList();
})
]),
builder: (context, snap) {
print(posts);
if(snap.connectionState == ConnectionState.done) {
return ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: 3,
itemBuilder: (context, index) {
return Text(userdata.displayName);
}
);
} else {
return Center(
child: Text('Loading')
);
}
}
)
full code:
late User user;
late Userdata userdata;
CollectionReference usersRef = FirebaseFirestore.instance.collection('users');
CollectionReference postsRef = FirebaseFirestore.instance.collection('posts');
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final auth = FirebaseAuth.instance;
late List<BlogPost> posts;
@override
Widget build(BuildContext context) {
user = auth.currentUser!;
Color getColor(Set<MaterialState> states) {
const Set<MaterialState> interactiveStates = <MaterialState>{
MaterialState.pressed,
MaterialState.hovered,
MaterialState.focused,
};
if (states.any(interactiveStates.contains)) {
return Colors.blue.shade900;
}
return Colors.blue.shade600;
}
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.blue,
child: Icon(
Icons.add,
color: Colors.white,
),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (_) => Upload()));
},
),
appBar: AppBar(
backgroundColor: Colors.grey[600],
actions: [
TextButton(
child: Text(
'Logout',
style: TextStyle(color: Colors.black),
),
onPressed: () {
auth.signOut();
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context) => LoginScreen()));
},
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith(getColor)
),
),
],
),
// body: Center(
// child: Text(user.uid)
// ),
body: FutureBuilder(
future: Future.wait([
usersRef.doc(user.uid).get().then((doc) {
userdata = Userdata.fromDocument(doc);
}),
postsRef.get().then((val) {
posts = val.docs.map((doc) => BlogPost.fromDocument(doc)).toList();
})
]),
builder: (context, snap) {
print(posts);
if(snap.connectionState == ConnectionState.done) {
return ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: 3,
itemBuilder: (context, index) {
return Text(userdata.displayName);
}
);
} else {
return Center(
child: Text('Loading')
);
}
}
)
);
}
}
class Userdata {
final String uid;
final String email;
final String displayName;
Userdata(this.uid, this.email, this.displayName);
factory Userdata.fromDocument(DocumentSnapshot doc) {
return Userdata(
doc['uid'],
doc['email'],
doc['displayName']
);
}
}
class BlogPost {
String displayName;
String postmsg;
String postId;
String UserId;
BlogPost(this.displayName, this.postmsg, this.postId, this.UserId);
factory BlogPost.fromDocument(DocumentSnapshot doc) {
return BlogPost(
doc['displayName'],
doc['postmsg'],
doc['postId'],
doc['UserId']
);
}
I figured out my problem, as out my code was fine the entire time I just had a typo in my fromDocument
my userId string was doc['UserId']
and was uploaded as 'userId'
just one misplaced Uppercase.
Thanks so much for the help