Reputation: 125
I'm trying to find whether the logged in user is an admin or a normal user.
I have already created a global function (then called it in initState
) to check whether the role is admin or not by setting a bool to true or false as follows:
bool isAdmin;
_checkRole() async {
var firebaseUser = FirebaseAuth.instance.currentUser;
await FirebaseFirestore.instance
.collection("users")
.doc(firebaseUser.uid)
.get()
.then((value) {
if ((value.data()['role']) == 'admin') {
isAdmin = true;
} else {
isAdmin = false;
}
return isAdmin;
});
}
And here in the drawer I did the following:
isAdmin
? buildListTile(
'Admin Panel', Icons.admin_panel_settings_sharp, () {
Navigator.of(context).pushNamed(AdminScreen.routeName);
})
: buildListTile('User dashboard', Icons.person, () {}),
But when I open the drawer, I receive Failed assertion: boolean expression must not be null
Any idea on how to fix this issue?
and thank you.
Upvotes: 0
Views: 379
Reputation: 605
Short answer:
isAdmin isn't initialized when you are building your ListTile because the async function hasn't had a chance to finish running.
Longer answer:
Your build
method happens synchronously with the rest of the code, meaning it happens one line after another. Your _checkRole()
method happens asynchronously, meaning it will get around to it whenever it gets around to it. So when you try initializing isAdmin
in your initState
method it is running a network call (which takes a long time in terms of program time) and waiting till the network call finishes to set isAdmin
. Meanwhile, your build is running and trying to build without knowing that it is supposed to wait for isAdmin
to be set.
A Solution:
(note, there are many ways to solve this, this is just one)
Use a FutureBuilder or StreamBuilder to load the variable and set the variable type to Future or the equivalent for streams and listen to the state change and build your UI accordingly.
Here's a basic example. Careful copy/pasting. I didn't run the code. This is just the general idea.
Future<bool> isAdmin;
FutureBuilder<String>(
future: Globals.isAdmin,
builder: (BuildContext context, AsyncSnapshot<Bool> snapshot) {
if (snapshot.hasData) { //
var isAdmin = snapshot.data;
// use the value for isAdmin
if (isAdmin == true) {
return Container();
} else {
return Container();
}
} else if (snapshot.hasError) {
//handle your error
return Container();
} else {
// handle your loading
return CircularProgressIndicator();
}
},
),
Upvotes: 2
Reputation: 599
Try to change your _checkRole() method the next way:
Future<bool> _checkRole() async {
var firebaseUser = FirebaseAuth.instance.currentUser;
return await FirebaseFirestore.instance
.collection("users")
.doc(firebaseUser.uid)
.get()
// we create the new Future with bool value, depending on
// the Firebase response and throw it away as a result of
// the _checkRole method
.then((value) => Future.value(value.data()['role']) == 'admin'));
}
And then use a FutureBuilder inside your component. So your layout should look like:
child: FutureBuilder<bool>(
future: _checkRole,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (snapshot.hasData) { // check whether we have any data in our Future object
final isAdmin = snapshot.data; // bool type
return isAdmin
? buildListTile(
'Admin Panel', Icons.admin_panel_settings_sharp, () {
Navigator.of(context).pushNamed(AdminScreen.routeName);
})
: buildListTile('User dashboard', Icons.person, () {}),
}
// if snapshot doesn't have data return a widget with an error message
return Center(
child: Text('Error!'),
);
},
),
Upvotes: 1
Reputation: 671
put a default value for isAdmin variable
bool isAdmin = false;
or If you have a model for members, I mean you created a class called Member
class Member {
// create a method for deteriming if the the member is an admin or not
bool isAdmin() async {
var firebaseUser = FirebaseAuth.instance.currentUser;
await FirebaseFirestore.instance
.collection("users")
.doc(firebaseUser.uid)
.get()
.then((value) {
return ((value.data()['role']) == 'admin');
});
}
}
Now, you can use this method to check if the member is an admin or not
Upvotes: 0