I am using Future to return some information from Firebase database that return Future .Now i wanted to convert bool.Here i am faceting null .But into the then function i found my value but when i return it its remain null.
Future<bool> _isfav(String post_key) async {
bool _is_fav;
await FirebaseDatabase.instance
.reference()
.child(Common.user)
.child(Common.number)
.child("favourite")
.child(post_key)
.once()
.then((v) {
print(v.value);
if (v.value != null) {
_is_fav = true;
} else {
_is_fav= false;
}
}).catchError((err) => print(err));
return _is_fav; }
This code perfectly fine .But now
bool read_fav(String index) {
bool data;
_isfav(index).then((v){
data= v;
print(data); /// printing data
});
print(data); //printing null
return data; //returning null }
When i print data into the then function its show my data but when i return it its return null.
i wanted calling the function from here
child: Icon(
Icons.favorite,
color:read_fav(_key[index])!=null && read_fav(_key[index]) == true
? Colors.blue
: Colors.black,
)),
Just follow the code like,
Future<bool> _isfav(String post_key) async {
bool _is_fav;
var snapData = await FirebaseDatabase.instance
.reference()
.child(Common.user)
.child(Common.number)
.child("favourite")
.child(post_key)
.once();
if (v.value != null) {
_is_fav = true;
} else {
_is_fav = false;
}
return _is_fav;
}
Future<bool> read_fav(String index) async{
bool data=false;
data=await _isfav(index);
return data;
}
Also, read_fav will be a future method. because it depends on _isFav() return value which will be predicted in future.
bool isReadFav=await read_fav(index);
Just refer dart await and then concepts at Here
You're all set.
Related
I'm trying to Use data that I fetched from database and i got an error : "LateInitializationError: Field 'check' has not been initialized. "
, i tried to remove the late word and adding " ? " and it gives another error "Expected a value of type 'num', but got one of type 'Null'
"
class _letterssState extends State<letterss> {
late var check;
Future getData() async{
var url = 'http://ip/getSpell.php';
http.Response response = await http.get(Uri.parse(url));
var data = jsonDecode(response.body);
check=data;
print(data.toString());
}
bool searchRes (String s){
int x=0;
for ( var i=0 ; i<check.length;i++ )
{
if (check[i]['letter']==s){
x=i;
}
}
if (check[x]['result']=='true')
{
return true;
}
else
{
return true;
}
}
initState()
{
getData();
}
It will take some frame to get data from getData future method and assigning on check.
It would better to use FutureBuilder for future methods. Follow this doc example
Future<List<yourDataType>?> getData() async {
var url = 'http://ip/getSpell.php';
http.Response response = await http.get(Uri.parse(url));
var data = jsonDecode(response.body);
return data;
}
late final future = getData();
#override
Widget build(BuildContext context) {
return FutureBuilder<List<YourDataType>?>(
future: future,
builder: (context, snapshot) {
if (snapshot.hasData) {
//todo:
}
return CircularProgressIndicator();
},
);
}
So for some background, I implemented a function that reads from Firebase's real-time database and returns a child node. I have built a button that is meant to check if that function returns the object or null if the function returns an object I want the snack bar to display a message.
ElevatedButton(
onPressed: () {
if (validateUsername() != null) {
print("conditional: test");
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text(
"Username has been taken please try a different one"),
duration: Duration(seconds: 5)));
} else {
return null;
}
},
I had some success with the function by turning it into an async function
validateUsername() async {
final database = FirebaseDatabase.instance.ref().child("/takenUsernames");
await database
.child(_usernameController.text.trim())
.once()
.then((DatabaseEvent event) {
final snapShot = event.snapshot;
final value = snapShot.value;
print("function result: $value");
return value;
});
}
When I turn it to an async function the snack bar displays the message but unfortunately even when the conditional is equal to a null, it for some reason continues to display the message and prints the "test"output. But if I were to try taking away the async the snack bar doesn't print and the "test" in the conditional doesn't print.non-async output
Any help would be appreciated and thanks for your time.
Try this approach, using the await in a variable will wait for the value then the if will evaluate what the result.
ElevatedButton(
onPressed: () async {
String validation = await validateUsername(); // I used type String but you should use the type that will be return.
if (validation != null) {
print("conditional: test");
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text(
"Username has been taken please try a different one"),
duration: Duration(seconds: 5)));
} else {
return;
}
},
)
add try/catch
validateUsername() async {
try {
final database = FirebaseDatabase.instance.ref().child("/takenUsernames");
await database
.child(_usernameController.text.trim())
.once()
.then((DatabaseEvent event) {
final snapShot = event.snapshot;
final value = snapShot.value;
print("function result: $value");
return value;
});
} catch(e) {
print("err $e");
return null;
}
}
Thanks to some help from #WilsonToribio, I was able to use the information he gave and also implement a few changes to the validateUsername() function
as seen here
validateUsername() async {
try {
final database = FirebaseDatabase.instance.ref().child("/usernames");
final response = await database
.child(_usernameController.text.trim())
.once()
.then((event) {
final dataSnapshot = event.snapshot;
if (dataSnapshot.value != null) {
return dataSnapshot.value;
}
});
return response;
} catch (e) {
print("err $e");
return null;
}
}
I am using a provider package. I want to display a loading spinner while waiting for a request to complete. The pattern below is too verbose. Please help me make it less verbose. Here is my code
class APIService with ChangeNotifier {
// Check for working API backend
bool isWorking = false;
bool isLoading = false;
set _isLoading(bool value) {
isLoading = value; <--
notifyListeners();
}
Future<bool> selectAPI(String input) async {
_isLoading = true; <-- 1
final uri = Uri.tryParse('https://$input$url')!;
final response = await http.get(uri);
if (response.statusCode == 200) {
final body = jsonDecode(response.body) as Map<String, dynamic>;
bool isTrue = body['info']['title'] == 'SamFetch';
_isLoading = false; <-- 2
notifyListeners();
return isWorking = isTrue;
}
_isLoading = false; <-- 3
throw response;
}
}
Here is my UI code
IconButton(
icon: apiService.isLoading
? CircularProgressIndicator()
: Icon(Icons.done),
onPressed: () async {
await addAPI(apiService, cache);
}),
}
Below is addAPI() method
Future<void> addAPI(APIService apiService, Cache cache) async {
if (api != null) {
try {
await apiService.selectAPI(api!);
if (apiService.isWorking) {
await cache.saveAppName(api!);
}
} on SocketException catch (e) {
print(e);
} catch (e) {
await cache.clearCache();
}
}
}
Is setState the final solution?
You can use Future Builder and set your Future Function in future attribute. You can control the visible widget based on the status of your function. So you dont have to use isloading variable.
I have this function that calls a Future<bool> function :
bool checkId(String id, context) {
bool ret;
checkMissingId(id, context).then((value) => ret = value);
return ret;
That calls :
Future<bool> checkMissingId(String id, context) async {
String str = id.toLowerCase();
String letter = str[0];
if (checkStr(id, letter, str) == false)
return false; //checks some rules on strings
else {
try {
var data = await FirebaseFirestore.instance
.collection("ids/tabs/" + letter)
.doc(str)
.get();
if (data.exists) {
return false;
} else
return true;
} catch (e) {
await showErrDialog(context, e.code);
return false;
}
}
}
ret returns null, not a bool value.
Edit : checkId must be of type bool, not Future<bool>
Because it is null when the checkId function returns. You should await the operation, like this:
Future<bool> checkId(String id, context) async {
bool ret = await checkMissingId(id, context);
return ret;
}
You need to pause the execution of the program for the checkMissingId method to complete before return the ret variable. You do this by using the await keyword and marking the function as async.
You should change the code to:
Future<bool> checkId(String id, context) async {
bool ret = await checkMissingId(id, context);
return ret;
}
I want to render something from Shared Preferences.
Here is my code :
return FutureBuilder<ChildModel>(
future: sharedPreference.getData(),
builder: (context, snapshot) {
print("SNAPSHOT" + snapshot.data.toString());
if (snapshot.hasData &&
snapshot.data != null) {
return _render(snapshot,context);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
} else {
return Text('Select Vehicle');
}
},
);
My SharedPreferece:
Future<ChildModel> getData() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
ChildModel singleObject ;
List<ChildModel> userVehicleList = [];
getSelectedVehicleID().then((onValue){
if(onValue!=null){
if (prefs.get(_kUserVehicles) != null) {
final List parsedList = json.decode(prefs.get(_kUserVehicles));
userVehicleList = parsedList.map<ChildModel>((val) => ChildModel.fromJson(val)).toList();
}
for (int i = 0; i < userVehicleList.length; i++) {
if (userVehicleList[i].id == onValue) {
singleObject = userVehicleList[i];
}
}
}
});
return singleObject ?? null;
}
The problem is singleObject = userVehicleList[i] is executed but doesnt return anything.
Always snapshot.data is null in Future Builder.
I want to return that singleObject that I found in that loop.
Can Anyone please help me with this ???
You are not awaiting for future to finish before returning value.
So
return singleObject ?? null;
will execute before
getSelectedVehicleID()
What you need is
int _selectedVehicleId = await getSelectedVehicleID();
And then continue getting anything from shared preferences and returning that.
Hope that will help :)