Snackbar won't show when included in .then - flutter

So I have reusable snackbar on my code and I wanted to show my snackbar when user already pop from certain page. I tried to put my snackbar inside .then but It wont show anything. Any idea how to fix this ?
Here's my code:
void openChangeClientPage(BuildContext context, user){
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddClientPage(
clientId: user!.uid,
clientNickname: Provider.of<UserDataProvider>(context, listen: false).userNickname,
clientProfileLink: Provider.of<UserDataProvider>(context, listen: false).userProfilePicture ?? '',
ticketData: ticketData,
ticketId: ticketId,
source: 'ticketDetail',
),
),
).then((value) {
if (value) {
ReusableSnackBar.buildSnackBar(context, 'New Client has been assigned');
Navigator.pop(context);
} else {
changeInvolvedState(true);
}
});
}

I think you can wrap the ReusableSnackBar into the Build method because snackbar tries to find the BuildContext closet but it is now in the Then method. You can read more in this
I think the code will be this:
void openChangeClientPage(BuildContext context, user){
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => AddClientPage(
clientId: user!.uid,
clientNickname: Provider.of<UserDataProvider>(context, listen: false).userNickname,
clientProfileLink: Provider.of<UserDataProvider>(context, listen: false).userProfilePicture ?? '',
ticketData: ticketData,
ticketId: ticketId,
source: 'ticketDetail',
),
),
).then((value) {
if (value) {
Builder(builder: (context)=>ReusableSnackBar.buildSnackBar(context, 'New Client has been assigned'));
Navigator.pop(context);
} else {
changeInvolvedState(true);
}
});}

The issue is that you are calling Navigator.pop immediately after calling ReusableSnackBar. This will cause the SnackBar to pop too because you can assume the snackbar is like a pop-up/dialog and is immediately dismissed.
You can call Navigator.pop before displaying the snackbar.
You can also check out this answer if you want to show snackbar without context.

Firstly, make sure condition ("value" variable) is true.
Remove this line in your code:
Navigator.pop(context);
This code will close current screen, not dismiss snack bar.
If you want to dismiss snack bar, use:
ScaffoldMessenger.of(context).hideCurrentSnackBar();

Related

Returning showDialog() as a Future does not trigger then() callback

I'm developing a flutter application and I am using showDialog() to show some errors that I've caught in catchError() method that I'm using for catching a potential exception for an api request.
i am returning showDialog() in catchError() as a Future result and im using then() after catchError() to know when showDialog() is poped to run some code as failure result of my request.
based on an online course that im watcing, showDialog() is resolved when we pop it from screens stack and i am using Navigator.of(context).pop(); to do that. but it's not working and it's not runing then() method.
I will be so grateful if anyone knows what's wrong.
this is my code and I hope it's clear enough.
Provider.of<Products>(context, listen: false)
.addProduct(Product(
id: edittedProduct.id,
title: edittedProduct.title,
description: edittedProduct.description,
price: edittedProduct.price,
imageUrl: edittedProduct.imageUrl,
isFavorite: edittedProduct.isFavorite))
.catchError((error) {
print("in second catchError method. error is: ${error.toString()}");
return showDialog<void>(
context: context,
builder: (ctx) => AlertDialog(
title: Text("An error occured!"),
content: Text("adding failed due to some issues."),
actions: [
TextButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("Okay"))
],
),
);
}).then((_) {
print("in second then method");
setState(() {
_isLoading = false;
});
Navigator.of(context).pop();
});

Call a method on page pop

I'm pushing a new route like so in my app
Navigator.of(context)
.push<void>(
FilterTypesPage.routeFullScreen(context),
).then(
(value) {
log('PAGGGE POPPED');
},
),
static Route routeFullScreen(BuildContext context) {
return MaterialPageRoute<void>(
settings: const RouteSettings(name: routeName),
builder: (_) => BlocProvider.value(
value: BlocProvider.of<FeatureBloc>(context),
child: const FilterTypesPage(),
),
fullscreenDialog: true);
}
for some reason log('PAGGGE POPPED'); doesn't get called on page close
I'd like to trigger a bloc event or a function when I close this page
You should just call
Navigator.pop(context, someData);
from your RouteSettings where someData is the data you want to pass from the RouteSettings to the former page.
Then from your former page, you can perform your event handling inside the then block. The value inside the then block is the data that was passed from the RouteSettings page.
Alternatively, you can also use async-await instead of then in your former page.
onPressed: () async {
final someData = await Navigator.of(cotext).push(.....);
// Now perform your event handling which will be invoked after you pop `RouteSettings` page.
}

Flutter: How to get data back after pushReplacement removed a route?

So it goes like this. Let's say I want to get the data of the address, title, postal code and the coordinate pin point.
I want to make the user click on a button that brings them to the second page an asks for coordinate pinpoint first, then in the third page, I will ask for their title, address, and postalCode.
CreatePreloved -> PinPointPage -> AddressPage
However i want the user the user to not go back to PinPointPage after they have submitted their coordinate so I used pushReplacement.
CreatePreloved -> AddressPage
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => ShoppingCreatePrelovedAddressPage(
pickResult: result,
),
),
);
Then in the AddressPage the user can edit the pinpoint so I changed the function after the user choosed the pin in PinPointPage
CreatePreloved -> AddressPage -> PinPointPage
if (widget.initialPick != null) {
Navigator.pop(context, widget.initialPick);
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => ShoppingCreatePrelovedAddressPage(
pickResult: result,
),
),
);
}
The problem is I cannot pass the data back to the CreatePrelovedPage
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ShoppingCreatePrelovedPinPage(),
),
).then((value) {
log('value: $value');
if (value != null) { //value is null
setState(() {
_addressModel = value;
log('value: $value');
});
}
});
It says the value is null. How to pass back to data to the CreatePrelovedPage?
can you please try in following method
CreatePreloved -> AddressPage
Navigator.of(context).pushNamed(
ShoppingCreatePrelovedAddressPage,
arguments: result,
);
and here need to use arguments by calling following code CreatePreloved -> AddressPage -> PinPointPage
final result = ModalRoute.of(context).settings.arguments as String;
Navigator.of(context).pushNamed(
ShoppingCreatePrelovedAddressPage,
arguments: result,
);
again same logic applies below send arguments while navigating
note:use routes in main.dart to navigate
final result = ModalRoute.of(context).settings.arguments as String;
Navigator.of(context).pushNamed(
ShoppingCreatePrelovedPinPage,
arguments: result,
);

Why using <Null> after showDialog?

Here I'm rendering an AlertDialog inside showDialog to display when error thrown from provider file. But that didn't work first time( Seems like stuck in catchError block, didn't execute future of catchError), Then I told to add <Null> after showDialog. That worked But How, What is changed, what it means?
Here is the code
if (_editedProduct.id == null) {
Provider.of<Products>(context, listen: false)
.addProduct(_editedProduct)
.catchError((error) {
return showDialog<Null>( //Here is that Null I didn't understand
context: context,
builder: (ctx) {
return AlertDialog(
title: Text('ERROR'),
content: Text('Error Occured'),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('I GOT IT'),
)
],
);
});
}).then((_) {
print('THEN');
setState(() {
isLoading = false;
});
Navigator.of(context).pop();
});
} else {
Provider.of<Products>(context, listen: false)
.updateProduct(_editedProduct.id, _editedProduct);
Navigator.of(context).pop();
}
}
Nb: isLoading true shows a circluarProgressIndicator()
From the Official Docs
Returns a Future that resolves to the value (if any) that was passed to Navigator.pop when the dialog was closed.
The place where you sent Null indicates the type of data the Future will return.
By using Null you are indicating that the Future won't return any data, this tell your program not to wait for the possible value that might be returned.
Suppose in your dialog user has to pick 2 numbers and you want the picked number to be returned to the place where you called the showDialog() function then you'll use int instead of Null.
Something like
showDialog<int>(...)

refresh previous page on Navigator.pop function

Is there any way to refresh the previous page/ stack when Navigator.pop(context) is called? I need to do the API calling of the previous page to refresh the state of the page. The navigator.pop will sometimes be an alert dialog or maybe a back button. Is there a way to do the API calling? ThankYou.
use the then function after you push another route.
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => MyHomePage(),
),
).then(
(value) {
if (value) {
//refresh here
}
},
);
and when you return to previous screen, provide the pop function a value that determines whether to perform some action.
Navigator.of(context).pop(true);
Previous page
void goToNextPage()async {
var refresh = await Navigator.push(_context, new MaterialPageRoute(
builder: (BuildContext context) => new nextPage(context))
);
if(refresh ) setState((){});
}
NextPage
Navigator.pop(context, true);