How to access future content - flutter

I have this function that is working inside a future builder:
Future<Data> fetchData(String barCode, String url) async {
final response = await http.get(Uri.parse(url + barCode));
Map<String, dynamic> novoJson = json.decode(utf8.decode(response.bodyBytes));
novoJson.forEach((key, value) {
if (value == null) {
novoJson.update(key, (value) => "Não encontrado");
}
});
if (response.statusCode == 200) {
return Data.fromJson(novoJson);
} else {
throw Exception('Failed to load album');
}
}
class Data {
final Map<String, dynamic> response;
Data({required this.response});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(response: json);
}
}
Now i'm trying to access the json it returns inside a ElevatedButton, like this:
onPressed: () {
if (_formKey.currentState!.validate()) {
var futureData = fetchData(myController.text, args.url);
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(title: animacaoRespostaApi());
});
futureData.whenComplete(() {
Navigator.of(context).pop();
print(futureData);
return Navigator.pushNamed(context, args.rota, arguments: ParametrosRetornoConsulta(myController.text, args.url));
});
}
}
But when print it I get an instance of Future instead of the object, and I can't access it's content with futureData['id'] for example.
How can I make futureData stop being an Future and become a iterable object ?

Future<Data> fetchData is Future, you need to use await for data.
onPressed: () async {
if (_formKey.currentState!.validate()) {
var futureData = await fetchData(myController.text, args.url);

Related

Flutter field has not been initialized

i have a bool that i set to true if the account datas is right but my bool is set to late and it doesnt works
My Model:
bool _result = false;
Future login(String username, String password) async {
var url = "http://192.168.178.75/flutterconn/login.php";
var response = await http.post(Uri.parse(url), body: {
"username": username,
"password": password,
});
var data = await json.decode(response.body);
if (data == "success") {
setResult(true);
Fluttertoast.showToast(msg: "Erfolgreich Eingeloggt",toastLength: Toast.LENGTH_SHORT,gravity: ToastGravity.CENTER,fontSize: 16.0);
}else {
Fluttertoast.showToast(msg: "Nicht Eingeloggt",toastLength: Toast.LENGTH_SHORT,gravity: ToastGravity.CENTER,fontSize: 16.0);
}
//print(_result);
notifyListeners();
}
Future setResult(bool rs) async{
_result = await rs;
notifyListeners();
}
bool getResult(){
return _result;
}
My onPressed Method:
context.read<LoginModel>().login(
usernameController.text, passwordController.text);
print(context.read<LoginModel>().getResult());
if (context.read<LoginModel>().getResult()) {
context.read<FoodSelectionModel>().loadGalleryLinks();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FoodSelectionScreen()),
);
}
My Error:
The following LateError was thrown while handling a gesture:
LateInitializationError: Field '_result#21188420' has not been initialized.
The Bool is turned to late to true how can i set it faster.
i tried with putting async on my onPressed method and await it works thank you guys.
onPressed: () async {
await context.read<LoginModel>().login(
usernameController.text, passwordController.text);
print(context.read<LoginModel>().getResult());
if (context.read<LoginModel>().getResult()) {
context.read<FoodSelectionModel>().loadGalleryLinks();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FoodSelectionScreen()),
);
}

flutter method checking if item is added to cart in firestore

I am having trouble with a method that is checking if the item is stored in the firestore database.
void add(BuildContext context, CartItem item) {
_items.add(item);
AuthService authService = Provider.of<AuthService>(context, listen: false);
Map<String, dynamic> cartMap = Map();
_items.forEach((CartItem item) {
cartMap['title'] = (item.product as Product).title;
cartMap['name'] = (item.product as Product).name;
});
_instance = FirebaseFirestore.instance;
_instance!
.collection('cart')
.doc(authService.getCurrentUser()) //need to get logged in account's id
.update({
'cartProduct': FieldValue.arrayUnion([cartMap])
}).then((value) {
print(_items.length);
notifyListeners();
});}
The add Method adds the item to the firestore in a way like the example image.
However, after I delete the data using the remove method,
void remove(BuildContext context, CartItem item) {
_items.remove(item);
AuthService authService = Provider.of<AuthService>(context, listen: false);
Map<String, dynamic> cartMap = Map();
// _items.forEach((CartItem item) {
cartMap['title'] = (item.product as Product).title;
cartMap['name'] = (item.product as Product).name;
// });
_instance = FirebaseFirestore.instance;
_instance!.collection('cart').doc(authService.getCurrentUser()).update({
'cartProduct': FieldValue.arrayRemove([cartMap]),
}).then((value) {
print(_items.length);
notifyListeners();
}); }
I check if the data is added to the cartProduct using isProductAddedToCart method and the result is still true. Also, when I print the _items.length, it doesn't decrease after I use the remove method.
bool isProductAddedToCart(Product? pro) {
return _items.length >= 0 ? _items.any(
(CartItem item) => item.product!.title == pro!.title) : false;
}
This is the code where I want to use the isProductAddedToCart method.
Consumer<CartService>(
builder: (context, cart, child) {
Widget renderedButton;
if (cart.isProductAddedToCart(widget.product) == false) {
renderedButton = DefaultButton(
text: "Participate",
press: () {
print(cart.isProductAddedToCart(widget.product));
cartService.add(context, CartItem(product: widget.product));
print(cart.isProductAddedToCart(widget.product));
},
);
} else {
renderedButton = DefaultButton(
text: "Delete",
press: () {
print(cart.isProductAddedToCart(widget.product));
cartService.remove(
context, CartItem(product: widget.product));
print(cart.isProductAddedToCart(widget.product));
},
);
}
return renderedButton;

flutter I want to get List<int> values ​as ints one by one

I want to get List values ​​as ints one by one.
where movieId requires an int value.
help me please
thank you
Future<MovieDetailModel> getMovieDetail(int? movieId) async {
try {
http.Response res = await http
.get(Uri.parse('$mainUrl/movie/$**movieId**?$apiKey&language=ko-KR'))
.timeout(Duration(seconds: 8),
onTimeout: () async => new http.Response('{}', 404));
if (res.statusCode == 404) {
return MovieDetailModel.fromJson({});
}
Map<String, dynamic> result = jsonDecode(res.body);
MovieDetailModel movies = MovieDetailModel.fromJson(result);
return movies;
} catch (e) {
print('MovieDetail $e');
}
return MovieDetailModel.fromJson({});
}
where user.userMovieId value is List .
Widget userMovie(UserModel user) {
return FutureBuilder(
future: this._movieDetailProvider.movies(**user.userMovieId!**),
builder:
(BuildContext context, AsyncSnapshot<MovieDetailModel> snapshot) {
if (snapshot.hasData) {}
Provider.
Future<MovieDetailModel> movies(int movieId) async {
MovieDetailModel movieList = await _movieRepo.getMovieDetail(movieId);
notifyListeners();
return movieList;
}

How to show SnackBar in class

i want call snack bar in this class on error method :
class serverRequest {
String _Url = "*****";
Future<String> getRequest(String Url, Map<String, dynamic> map) async {
String BaseUrl = _Url + Url;
var dio = Dio();
print(BaseUrl.toString());
dio.interceptors
.add(InterceptorsWrapper(onRequest: (RequestOptions options) async {
print("REQUEST[${options?.method}] => PATH: ${options?.path}");
return options; //continue
}, onResponse: (Response response) async {
print(
"RESPONSE[${response?.statusCode}] => PATH: ${response?.request?.path}");
return response; // continue
}, onError: (DioError err) async {
print("ERROR[${err.toString()}] => PATH: ${err?.request?.path}");
if (err.response.statusCode == 403) {
// i want call snack bar here
}
return err; //continue
}));
Response response = await dio.post(BaseUrl, queryParameters: map);
print(response.toString());
return response.toString();
}
dynamic requestInterceptor(RequestOptions options) async {
return options;
}
this serverRequest class call in some pages for request and i want when have server error show snack bar in app.
you can add an extra argument to the ```getRequest`` method like so
class serverRequest {
String _Url = "*****";
Future<String> getRequest(String Url, Map<String, dynamic> map, Function onError) async {
////
if (err.response.statusCode == 403) {
// i want call snack bar here
onError(statusCode);
}
and when your calling this function in your widget, you can pass this
Function showErrorSnackBar(errorCode) {
Scaffold.of(context).showSnackBar(
SnackBar(
)
)
}
/// where you call it, pass this function
MaterialButton(
// other props
onPressed: () {
serverRequest().getRequest(x,y, showErrorSnackBar)
}
)

Show dialog using Scoped model

I have a basic login form, with my LoginModel.
But I do not understand how I can call to the function notifyListeners to display a dialog in my view.
The login widget:
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new ScopedModel<LoginModel>(
model: _loginModel,
child: Center(child: ScopedModelDescendant<LoginModel>(
builder: (context, child, model) {
if (model.status == Status.LOADING) {
return Loading();
}
else return showForm(context);
}))));
}
And the login model:
class LoginModel extends Model {
Status _status = Status.READY;
Status get status => _status;
void onLogin(String username, String password) async {
_status = Status.LOADING;
notifyListeners();
try {
await api.login();
_status = Status.SUCCESS;
notifyListeners();
} catch (response) {
_status = Status.ERROR;
notifyListeners();
}
}
I need to display a dialog when the status is Error
Finally I got this, just returning a Future in the method onLogin
Future<bool> onLogin(String username, String password) async {
_status = Status.LOADING;
notifyListeners();
try {
await api.login();
_status = Status.SUCCESS;
notifyListeners();
return true;
} catch (response) {
_status = Status.ERROR;
notifyListeners();
return false;
}
}
And in the widget:
onPressed: () async {
bool success = await _loginModel.onLogin(_usernameController.text, _passwordController.text);
if(success) {
Navigator.pop(context, true);
}
else{
_showDialogError();
}
}