i have a method that changes a static boolean variable that i want to use to conditionally display a button widget, the value is set to true if a condition is met else it is set to false, when i print the value of the variable inside the method it displays the expected boolean value, but the problem is when i call that boolean variable from another class it doesnt print out the expected value even if the condition is met, sometimes it will still print out true even when the condition is not met, and vice versa
I created the method here
class GetBool {
//THIS IS THE VARIABLE I WANT TO BE CHANGING ITS VALUE
static bool? isAdded;
}
void getBool(String model) async {
print("function ran");
User? user = FirebaseAuth.instance.currentUser;
DocumentSnapshot<Map<String, dynamic>> document = await FirebaseFirestore
.instance
.collection("Cart")
.doc(user!.uid)
.get();
DocumentReference docRef =
FirebaseFirestore.instance.collection("Cart").doc(user.uid);
List list = [];
for (var doc in document.data()!['cart'] as Iterable) {
list.add(doc['model']);
print("model says before condition $model");
print("list is $list");
if (list.contains(model)) {
GetBool.isAdded = true;
print("this item exist");
print(GetBool.isAdded);
} else {
GetBool.isAdded = false;
print("this item doesnt exist");
print(GetBool.isAdded);
}
}
}
this is where i call the method
class WatchTile extends StatefulWidget {
final Watch? watch;
const WatchTile({this.watch, super.key});
@override
State<WatchTile> createState() => _WatchTileState();
}
class _WatchTileState extends State<WatchTile> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.pushNamed(
context,
"/watch_details",
arguments: widget.watch,
);
//I CALL THE METHOD HERE WHEN I NAVIGATE TO watch_details.dart
DatabaseService().getBool(widget.watch!.model!);
},
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: Column(
children: <Widget>[
Container(
height: 200,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(widget.watch!.image!),
fit: BoxFit.cover)),
),
Container(
padding: const EdgeInsets.only(left: 4.0),
width: double.maxFinite,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.watch!.brand!,
style: const TextStyle(color: Colors.grey),
),
Text(widget.watch!.model!),
Text('$${widget.watch!.price!}'),
],
),
)
],
),
),
);
}
}
watch_details.dart
final FirebaseAuth auth = FirebaseAuth.instance;
User? user = auth.currentUser;
class WatchDetail extends StatefulWidget {
const WatchDetail({super.key});
@override
State<WatchDetail> createState() => _WatchDetailState();
}
class _WatchDetailState extends State<WatchDetail> {
final DatabaseService _database = DatabaseService();
int itemQuantity = 1;
@override
Widget build(BuildContext context) {
print("getbool says ${GetBool.isAdded}");
final watch = ModalRoute.of(context)?.settings.arguments as Watch;
print("route args is ${watch.brand}");
return Scaffold(
appBar: AppBar(
title: Text(watch.brand!),
),
body: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
//THIS IS WHERE I WANT TO CONDITIONALLY DISPLAY A WIDGET
child: GetBool.isAdded == false
? ElevatedButton(
style: ButtonStyle(),
onPressed: () async {
await _database.addToCart(watch.model!, watch.brand!,
itemQuantity, int.parse(watch.price!));
},
child: Text("Add To Cart"),
)
: ElevatedButton(
onPressed: () {}, child: Text("Added To Cart")),
),
],
)
],
),
);
}
}
2
Answers
i ended up changing the return type of the getBool method to a Future like so
then in my watch_details.dart i wrapped my "add to cart" button with a future builder, so
snapshot.data
will return the value of the getBool function(either true or false) and the add to cart button will change depending on the valueThe problem is not where you call the
isAdded
variable, but when you call it.Since the data is loaded from Firestore asynchronously, any code that wants to use the value from the database has to wait until that data is available.
In your
getBool
function you do that by usingawait
here:The
await
here ensures that thedocument
is loaded before the rest of the code ingetBool
executes.But the other that that accesses the
isAdded
value is not usingawait
to wait for the data to load, so it sees whatever value is available whenever that code executes.If you want to ensure the data is loaded from the database before the code uses it, you’ll have to use a
Future<bool>
instead of thebool?
that you have forisAdded
now.This is an incredibly common problem when dealing with modern web/cloud APIs, so I recommend reading up on how to handle such APIs in your own code on Asynchronous programming: futures, async, await, Async Widgets and Async/Await – Flutter in Focus