Comments (13)
I'm currently displaying a dialog when my API throws an error.
The problem I'm running into is that I'm making mulitple calls at the same time, and sometimes I get multiple errors, so I end up with getting multiple dialogs open at the same time.
Is there a way to prevent this? Or is there a way to figure out if there is currently a dialog open? So I can check for that before displaying the dialog.
This code snippet should resolve most of your issues.
You are exposing the routing of your Middleware in a Global way through a singleton.
There are endless ways to do this, but if you are not using any state manager, it is the most practical way to do this.
class MiddleWare {
static MiddleWare _instance;
factory MiddleWare() {
if (_instance == null) _instance = MiddleWare._();
return _instance;
}
MiddleWare._();
static Routing _routing;
static Routing get routing => _routing;
static observer(Routing rt) {
_routing = rt;
}
}
class Foo {
openDialog() {
if(!MiddleWare.routing.isDialog){
// or if(MiddleWare.routing.isDialog) Get.back(); to close dialog and open other
Get.dialog(YourDialogClass())
}
}
}
Middleware.rounting will give you everything you need. Current route, if you have an open dialog, if you have an open snackbar, if you have an open bottomsheet, if the open route is "x" or "y", and anyway, you can use this approach.
Later on you can create your own approach using your favorite state manager, or reactive programming.
from getx.
Looks like whatever sets the routing.isDialog to true is not fast enough, because I'm still getting dual dialogs when 2 api connections fail at the same time.
Any other ideas?
from getx.
if(!MiddleWare.routing.isDialog){
is on 2 apis ?
from getx.
I'm trying to reproduce the problem, but I'm not getting it.
Are you making two requests to the api at the same time, and are you turning off the internet or something? or is the error an error response from your own API?
This should not happen for the simple reason that there are no parallel routes. As soon as the dialog is opened, it instantly notifies Middleware. Unless the second dialog is called before the first is opened.
It is a case to think about.
from getx.
For testing purposes only, does adding await before Get.dialog change anything?
await Get.dialog(YourDialogClass());
from getx.
It's multiple requests to an api that expires an auth token.
This is my request method:
static Future<dynamic> post(String endpoint, {Object params}) async {
Map<String, String> headers = {"Content-Type": "application/json"};
LoginResultsDTO loginResults = CurrentUser().loginResults;
if (loginResults?.oAuth?.accessToken != null &&
loginResults?.oAuth?.tokenType != null) {
headers['Authorization'] =
loginResults.oAuth.tokenType + ' ' + loginResults.oAuth.accessToken;
}
final body = params == null ? null : jsonEncode(params);
print('\n${URLS.BASE_URL}$endpoint\n${params ?? ''}');
final response = await http.post('${URLS.BASE_URL}$endpoint',
headers: headers, body: body);
if (response.statusCode == 200) {
if (response.body.length == 0) return true;
return json.decode(response.body);
} else {
if (response.body != null) {
ErrorDTO error = ErrorDTO.fromJson(json.decode(response.body));
if (error.raw != null) {
switch (error.code) {
case ServerError.authorizationExpired:
print('Try to refresh token');
if (loginResults != null) {
OAuthDTO refreshOAuth = await AuthenticationService.refresh(
loginResults.oAuth?.refreshToken,
loginResults.user?.userID);
var refreshLoginResults =
LoginResultsDTO.withOAuth(refreshOAuth, loginResults);
CurrentUser().setLoginResults(refreshLoginResults);
return await Api.post(endpoint, params: params);
}
throw ServerException('No login results', error);
break;
case ServerError.authorizationFailed:
case ServerError.invalidAuthorizationToken:
CurrentUser().setLoginResults(null);
if (!MiddleWare.routing.isDialog) {
print('error dialog');
await Get.defaultDialog(
title: 'Error',
content: Text(error.code.description),
confirm: FlatButton(
child: Text('OK'),
onPressed: () {
Get.until(Routes.Login, (Route route) {
return route.isFirst;
});
},
),
);
}
//throw ServerException(error.code.description, error);
break;
case ServerError.Unknown:
print(error.raw);
throw ServerException(error.raw, error);
break;
}
}
} else {
print(response.toString());
throw Exception('Failed');
}
}
}
from getx.
Well, I did a lot of tests, including sending the context by parameter to test if this behavior is a Get problem, and I found out that this is the default behavior of the framework, and that you must implement your own logic to prevent this from happening.
I didn't close this question because I intend to help you with that.
Are you sure your error code is not making a double call? Try this
static Future<dynamic> post(String endpoint, {Object params}) async {
Map<String, String> headers = {"Content-Type": "application/json"};
bool isDialogOpen = false; // ADD THIS
LoginResultsDTO loginResults = CurrentUser().loginResults;
if (loginResults?.oAuth?.accessToken != null &&
loginResults?.oAuth?.tokenType != null) {
headers['Authorization'] =
loginResults.oAuth.tokenType + ' ' + loginResults.oAuth.accessToken;
}
final body = params == null ? null : jsonEncode(params);
print('\n${URLS.BASE_URL}$endpoint\n${params ?? ''}');
final response = await http.post('${URLS.BASE_URL}$endpoint',
headers: headers, body: body);
if (response.statusCode == 200) {
if (response.body.length == 0) return true;
return json.decode(response.body);
} else {
if (response.body != null) {
ErrorDTO error = ErrorDTO.fromJson(json.decode(response.body));
if (error.raw != null) {
switch (error.code) {
case ServerError.authorizationExpired:
print('Try to refresh token');
if (loginResults != null) {
OAuthDTO refreshOAuth = await AuthenticationService.refresh(
loginResults.oAuth?.refreshToken,
loginResults.user?.userID);
var refreshLoginResults =
LoginResultsDTO.withOAuth(refreshOAuth, loginResults);
CurrentUser().setLoginResults(refreshLoginResults);
return await Api.post(endpoint, params: params);
}
throw ServerException('No login results', error);
break;
case ServerError.authorizationFailed:
case ServerError.invalidAuthorizationToken:
CurrentUser().setLoginResults(null);
if (!isDialogOpen) { // CHANGE THIS
isDialogOpen = true;
print('error dialog');
Get.defaultDialog(
title: 'Error',
content: Text(error.code.description),
confirm: FlatButton(
child: Text('OK'),
onPressed: () {
Get.until(Routes.Login, (Route route) {
return route.isFirst;
});
},
),
);
}
//throw ServerException(error.code.description, error);
break;
case ServerError.Unknown:
print(error.raw);
throw ServerException(error.raw, error);
break;
}
}
} else {
print(response.toString());
throw Exception('Failed');
}
}
}
from getx.
Ok, here is a fully reproducible code:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:rpm/middleware.dart';
class TestScreen extends StatelessWidget {
void login() {
getTestError();
getTestError();
}
Future<dynamic> getTestError() async {
final response =
await http.get('http://www.mocky.io/v2/5e97d4673000007900b6e08c');
if (response.statusCode == 200) {
return response.body;
} else {
if (MiddleWare.routing.isDialog == null ||
MiddleWare.routing.isDialog == false) {
print('error dialog');
await Get.defaultDialog(
title: 'Error',
content: Text('There was an error'),
confirm: FlatButton(
child: Text('OK'),
onPressed: () {
Get.back();
},
),
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: FlatButton(
child: Text('Test'),
onPressed: login,
),
),
),
);
}
}
Your addition with the isDialogOpen
doesn't help either
from getx.
Thanks for opening this issue, after the reproduction code I was able to trace the root of the problem, and GetObserver is improved now. Can you reproduce the problem using version 1.16.1-dev?
Unfortunately my Macbook is not turning on (I burn the midnight oil trying to get it to turn on), and I made the correction to the stable branch that was installed on my personal notebook. I made the correction to the dev branch by the text editor, so ... I'm not sure it's working, but I hope it works for you.
from getx.
Nice!! It seems to be working on the test snippet. I'll implement it in the app now and let you know how it goes
from getx.
Flawless! Thanks!!
from getx.
New API added
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:http/http.dart' as http;
import 'package:rpm/middleware.dart';
class TestScreen extends StatelessWidget {
void login() {
getTestError();
getTestError();
}
Future<dynamic> getTestError() async {
final response =
await http.get('http://www.mocky.io/v2/5e97d4673000007900b6e08c');
if (response.statusCode == 200) {
return response.body;
} else {
if (!Get.isDialogOpen) { // Now you can made this
print('error dialog');
await Get.defaultDialog(
title: 'Error',
content: Text('There was an error'),
confirm: FlatButton(
child: Text('OK'),
onPressed: () {
Get.back();
},
),
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child: FlatButton(
child: Text('Test'),
onPressed: login,
),
),
),
);
}
}
from getx.
Great! I verified it. Works like a charm
from getx.
Related Issues (20)
- Get.snackbar() doesn't work successfully when starting the app for the first time. HOT 3
- [GetMiddleware] RouteDecoder.fromRoute can't Jump
- Flutter web deepLink HOT 4
- Using Base URL for graphql requests doesn't work
- 你们的PopScope正常嘛,我这边canPop=false时在iOS上依然能够侧滑返回,android上倒是正常 HOT 8
- 能否说明下 Get5 的路由 HOT 1
- Flutter web Getx routing dynamic API extension for testing
- Got status 3xx with followRedirects is true
- KINDLY COMMUNICATE WITH COMMUNITY PLEASE ( dear developer) you are making us loose hope HOT 8
- RTL Icon Padding Issue in Get.rawSnackbar() HOT 1
- PosScope in IOS while using Getx Route management. HOT 6
- Get.to 为什么在第一次跳转的时候当前route没有过渡效果
- Flutter getx trparams (@ variables substitution) does not work for Hebrew locale. Reported in StackOverflow.com HOT 3
- get.snackbar's selfsize
- Hot reload does not work in Windows HOT 1
- getx update not trigger ui refresh in time
- RouterReportManager base on _current to delete Controller is Not a good idae HOT 3
- same page transition issue
- XMLHttpRequest error in get request (web ) HOT 1
- how get GetMaterialApp instance?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from getx.