I am working on a shopping app where I need to save the user input data to server. While sending the data, I want to handle exceptions, if any. But, .catchError() block is not working.
the code:
void _saveForm() {
final isValid = _form.currentState!.validate();
if (!isValid) {
return;
}
_form.currentState!.save();
setState(() {
_isLoading = true;
});
if (ModalRoute.of(context)!.settings.arguments as String == "add") {
Provider.of<Products>(context, listen: false)
.addProduct(_editedProduct)
.catchError((error) {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text("Somethiinng went wrong"),
content: Text(error.toString()),
actions: <Widget>[
FloatingActionButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text("Okay"),
)
],
));
}).then((_) {
setState(() {
_isLoading = false;
});
});
Navigator.of(context).pop();
} else {
Provider.of<Products>(context, listen: false).updateProduct(
ModalRoute.of(context)!.settings.arguments as String, _editedProduct);
Navigator.of(context).pop();
}
}
It is the provider file where I am sending data and intentionally removed .json
after the link which causes the exception.
Future<void> addProduct(Product product) {
final url = Uri.parse(
'https://food-fancy-default-rtdb.firebaseio.com/products');// removed .json after products
return http
.post(url,
body: json.encode({
"title": product.title,
"price": product.price,
"description": product.description,
"imageUrl": product.imageUrl,
"isFavorite": product.isFavorite
}))
.then((response) {
final _newProduct = Product(
id: json.decode(response.body)["name"],
title: product.title,
description: product.description,
price: product.price,
imageUrl: product.imageUrl);
_items.insert(0, _newProduct);
print(json.decode(response.body));
notifyListeners();
}).catchError((error) {
throw error;
});
}
Error message:
> E/flutter (11843): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: This widget has been unmounted, so the State no longer has a context (and should be considered defunct).
>
> E/flutter (11843): Consider canceling any active work during "dispose" or using the "mounted" getter to determine if the State is still active.
I have tried
Navigator.pop()
Navigator.of(context, rootNavigator: true).pop()
CodePudding user response:
this ModalRoute.of(context)!.settings.arguments as String
is not correct because the ModalRoute.of(context)!.settings.arguments
is a map and you can't cast it to a String so what you need to do is to access the keys inside of it, for instance if you're sending a key called 'add'
with the value true
you need to acces it like this:
Map<String, dynamic>? _data = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>?;
_result = _data!['add'];
and the result should be true now.
CodePudding user response:
The problem solved if I use try
catch
. blocks in async
the code:
void _saveForm() async {
final isValid = _form.currentState!.validate();
if (!isValid) {
return;
}
_form.currentState!.save();
setState(() {
_isLoading = true;
});
if (ModalRoute.of(context)!.settings.arguments as String == "add") {
try {
await Provider.of<Products>(context, listen: false)
.addProduct(_editedProduct);
} catch (error) {
await showDialog(
// returning the result of showDialogg()
context: context,
builder: (ctx) => AlertDialog(
title: const Text("Somethiinng went wrong"),
content: Text(error.toString()),
actions: <Widget>[
ElevatedButton(
child: const Text("Okay"),
onPressed: () {
Navigator.of(ctx).pop();
},
)
],
));
} finally {
setState(() {
_isLoading = false;
});
Navigator.of(context).pop();
}
} else {
Provider.of<Products>(context, listen: false).updateProduct(
ModalRoute.of(context)!.settings.arguments as String, _editedProduct);
Navigator.of(context).pop();
}
}`