How to make Alert Dialog working in flutter - flutter

I am using below code to register the user, there is an option to upload image , if it is null the user won't be registered, that is working accurately, only thing I am facing is that if the image is null it should the alert dialog to the user , but the alert dialog is not working at all.
How should I implement the alert dialog?
if (avatarImageFile != null ) {
FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: emailInputController.text,
password: pwdInputController.text)
.then((currentUser) =>
Firestore.instance
.collection("users")
.document(currentUser.user.uid)
.setData({
"username": userNameInputController.text,
"email": emailInputController.text,
})
.then((result) =>
{
uploadFile(currentUser.user.uid),
print(currentUser.user.getIdToken()),
currentUser.user.sendEmailVerification(),
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) =>
MainScreen(
)),
(_) => false),
})
.catchError((err) => print(err)))
.catchError((err) => print(err));
}
else {
print("Please Upload the Image");
AlertDialog(
title: Text("Image Required"),
content: Text("Please upload the image"),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
}

You need to use the function showDialog so the dialog appears:
else {
print("Please Upload the Image");
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Image Required"),
content: Text("Please upload the image"),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
};
);
}

Peter Haddad's answer solves the problem but I would suggest placing the AlertDialog in a widget so that it would be easy to reuse the AlertDialog again. Here is how I did it for my project:
Dialogs.dart:
import 'package:flutter/material.dart';
enum alertDialogAction { cancel, save }
class Dialogs {
static Future<alertDialogAction> alertDialog(
BuildContext context,
String title,
String body,
String cancel,
String save,
) {
Future<alertDialogAction> action = showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
title: Text(title),
content: Text(body),
actions: <Widget>[
FlatButton(
onPressed: () =>
Navigator.pop(context, alertDialogAction.cancel),
child: Text(cancel)),
RaisedButton(
color: Colors.orange,
onPressed: () =>
Navigator.of(context).pop(alertDialogAction.save),
child: Text(
save,
style: TextStyle(color: Colors.white),
)),
],
);
});
return (action != null) ? action : alertDialogAction.cancel;
}
Here is how you can call it:
onPressed:() async {
final action= await Dialogs.alertDialog(context,"Title","Body","Cancel","Save");
//cancel and save are the button text for cancel and save operation
if(action==alertDialogAction.save){
//do something
Navigator.pop(context);
}
}

You can also show a dialog box using scaffold, for example,
Scaffold.of(context).showSnackBar(SnackBar(content: AlertDialog(content: Text('Alert!!!'))));
But you have to keep in mind that context should be of the current scaffold.
So you might want to wrap the body property (in Scaffold) in a Builder Widget and then when you use context inside that builder widget, that context will be of current scaffold.

showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Your Title!!!"),
content: Text("Your Content!!!"),
actions: <Widget>[
FlatButton(
child: Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
};
);

Related

How use alert dialog flutter

I try building alert function, but this error follow return:
Undefined name 'context'.
Try correcting the name to one that is defined, or defining the name.
Future<void> _showAlertDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
// <-- SEE HERE
title: const Text('Cancel booking'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text('Are you sure want to cancel booking?'),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('No'),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: const Text('Yes'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
I would like to click on a certain elevatedbutton to open the alert dialog
Try to pass the current BuildContext to your function
Future<void> _showAlertDialog(BuildContext context) async {

How to close severals showDialogs in flutter

How can I to close all the showDialogs in my aplication? in this case _mostrarDialogConfirmacion is the dialog where i request to the user a confirmation to make a query, cargandoDialog is another dialog where i show a loading message while the query is executing, when the query finish, i want to close the two dialogs and only see the _mostrarDialogMensaje dialog
_mostrarDialogConfirmacion(
mensaje,
BuildContext context,
codLink,
motivo,
) {
return showDialog(
context: context,
builder: (context){
return AlertDialog(
title: const Text(
'Informacion',
textAlign: TextAlign.center,
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget> [
Text(mensaje, textAlign: TextAlign.center),
],
),
actions: <Widget> [
TextButton(
onPressed: () async {
Navigator.of(context).pop();
cargandoDialog(context);
List<dynamic> ingresarReclamo1 = await ingresarReclamo
.ingresarReclamo(codLink, titular, motivo);
// ignore: use_build_context_synchronously
Navigator.of(context).pop();
// ignore: use_build_context_synchronously
_mostrarDialogMensaje(
ingresarReclamo1[0].observaciones,
ingresarReclamo1[0].validado,
context,
);
},
child: const Text('Si')
),
TextButton(
onPressed: ()=> Navigator.of(context).pop(),
child: const Text('No')
),
],
);
}
);
}
you will dismiss first dialog and then you can use whenComplete to dismiss the second dialog
showDialog(
.....
).whenComplete(() => Navigator.of(context).pop())
You can return bool while .pop(boolValue) to check the tap button. Also, the showDialog is a future method, you can use await until it finished and then processed to next dialog. Navigator.of(context).pop() will be used to close recent dialog on this case. As for my understanding about the question, try this example code.
_mostrarDialogConfirmacion(mensaje, BuildContext context, codLink, motivo) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: const Text('Informacion', textAlign: TextAlign.center),
content: Column(
mainAxisSize: MainAxisSize.min,
),
actions: <Widget>[
TextButton(
onPressed: () async {
// Navigator.of(context)
// .pop(); //if you like to close previous one before showing the next dialog
final bool isSi = await showDialog(
barrierDismissible: false,
builder: (context) => AlertDialog(
content: Text("Second Dialog"),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: const Text('Si')),
TextButton(
onPressed: () =>
Navigator.of(context).pop(false),
child: const Text('No')),
],
),
context: context);
if (mounted && isSi) {
Navigator.of(context).pop();
await showDialog(
builder: (context) => AlertDialog(
content: Text("_mostrarDialogMensaje")),
context: context);
}
},
child: const Text('Si')),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('No')),
],
);
});
}

How to go back to the previous screen when the dialog is dismissed?

I have a problem. I would like to pop the screen (of main context) when alert dialog is closed.
So here how it goes:
User does some staff.
Alert dialog is open
It is open for 3 seconds.
Alert dialog is closed
We move user to the main screen (EmailPage for me)
Whole method:
Future<void> _sendMessageToSupport() async {
final body = {
'email': emailController.text, //
'topic': topicController.text, //
'message': contentController.text,
};
final jsonString = json.encode(body);
final uri =
Uri.http(AppConstants.BASE_URL, AppConstants.SUPPORT_CONTACT_ENDPOINT);
final headers = {HttpHeaders.contentTypeHeader: 'application/json'};
_setRefreshProgressIndicator(true);
await http.post(uri, headers: headers, body: jsonString);
_setRefreshProgressIndicator(false);
showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
Future.delayed(
Duration(seconds: 3),
() {
Navigator.of(context).pop(true);
/*Navigator.push(context,
new MaterialPageRoute(builder: (context) => EmailPage()));*/ //navigates to EmailPage rather than pop to it
},
);
return AlertDialog(
title: Text(
'blabla',
style: TextStyle(
fontSize: 18,
color: Color(0xff000000),
),
textAlign: TextAlign.center,
),
);
},
);
}
We move to this screen (let's say A screen) from the EmailPage. User does staff and we should automatically back to the EmailPage. I have made it like this:
Future.delayed(
Duration(seconds: 3),
() {
Navigator.of(context).pop(true);
/*Navigator.push(context,
new MaterialPageRoute(builder: (context) => EmailPage()));*/ //navigates to EmailPage rather than pop
},
);
but the problem is we move user to EmailPage by pushing new screen and then when he clicks on the back arrow on the appbar he is moved to screen A again.
Could you tell me how can I do it? I mean, I know that I need to pop from context of build method, but how? When I did something like this (pop on the end of the method):
builder: (context) {
Future.delayed(
Duration(seconds: 3),
() {
Navigator.of(context).pop(true);
/*Navigator.push(context,
new MaterialPageRoute(builder: (context) => EmailPage()));*/ //navigates to EmailPage rather than pop
},
);
return AlertDialog(
title: Text(
'Wysłano zapytanie do supportu. Postaramy się odpowiedzieć jak najszybciej!',
style: TextStyle(
fontSize: 18,
color: Color(0xff000000),
),
textAlign: TextAlign.center,
),
);
},
);
Navigator.of(context).pop(true);
}
then popup was not even shown.
Let me know if this is not what you're looking for.
class EmailPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('EmailPage')),
body: Center(
child: ElevatedButton(
onPressed: () => Navigator.push(context, MaterialPageRoute(builder: (_) => PageA())),
child: Text('Go to Page A'),
),
),
);
}
}
class PageA extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('PageA')),
body: Center(
child: ElevatedButton(
onPressed: () {
Timer(Duration(seconds: 3), () {
Navigator.pop(context); // Dismisses dialog
Navigator.pop(context); // Navigates back to previous screen
});
showDialog(
context: context,
builder: (_) => AlertDialog(
title: Text('Dialog'),
content: Text('Dismissing in 3s'),
),
);
},
child: Text('Show Dialog'),
),
),
);
}
}
The Alert Dialog returns a future that runs when the Dialog is Closed so you can subscribe to that future and use your pop code inside that future. /
Here is a simple example to showcase
RaisedButton(
onPressed: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Are you sure?'),
content: Text('Do you want to remove item?'),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.of(context).pop('Success'),
child: Text('NO')),
FlatButton(
onPressed: () => Navigator.of(context).pop('Failure'),
child: Text('YES'))
],
)).then((value) =>
print('Result: ' + value.toString()));
},
child: Text('Show Alert Dialog'),
),

AlertDialog not closing Flutter

my button code is as below and previously it closed the AlertDialog + Signed Out of Google when clicking on the continue button, but now it only signs out, the AlertDialog is still there... Anyone knows whats going on?
showAlertDialog(BuildContext context) {
// set up the buttons
Widget cancelButton = FlatButton(
child: Text("Cancel"),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop();
},
);
Widget continueButton = FlatButton(
child: Text("Confirm Sign Out"),
onPressed: () {
signOutGoogle();
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) {
return LoginPage();
}), ModalRoute.withName('/'));
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("Confirmation"),
content: Text("Are you sure you want to Sign Out?"),
actions: [
cancelButton,
continueButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
showAlertDialog invoked here :
RaisedButton(
onPressed: () {
showAlertDialog(context);
},
color: Colors.deepPurple,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Sign Out',
style: TextStyle(fontSize: 25, color: Colors.white),
),
),
elevation: 5,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40)),
)
Add Navigator.of(context).pop(); after signOutGoogle(); to close the dialog.
showAlertDialog(BuildContext context) {
// set up the buttons
Widget cancelButton = FlatButton(
child: Text("Cancel"),
onPressed: () {
Navigator.of(context, rootNavigator: true).pop();
},
);
Widget continueButton = FlatButton(
child: Text("Confirm Sign Out"),
onPressed: () {
signOutGoogle();
Navigator.of(context).pop(); // Pop the dialog
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) {
return LoginPage();
}), ModalRoute.withName('/'));
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("Confirmation"),
content: Text("Are you sure you want to Sign Out?"),
actions: [
cancelButton,
continueButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}

How to change a button's text, based on input on text field

I have a small popup with a button "DELETE", however I want to change the text to "SELL" everytime the input text is different than 0.00
showDialog(
context: context,
builder: (context) {
String _popUpDeleteSoldText = "Delete";
return AlertDialog(
title: Text("Delete " + doc['propertyName'] + "?"),
content: Container(
height: 120,
child: Column(
children: <Widget>[
TextField(
onChanged: (text) {
if (text != "0.00") {
print("i'm != 0.00");
setState(() {
//TODO - THIS AIN'T WORKING
_popUpDeleteSoldText = "Sell";
});
} else {
print("i'm still 0");
setState(() {
_popUpDeleteSoldText = "Delete";
});
}
},
the button:
MaterialButton(
elevation: 4.0,
child: Text(
_popUpDeleteSoldText,
style: TextStyle(color: Colors.white),
)
....
The print are working on the onChange function, but the button text always say "Delete"
I would suggest to extract your AlertDialog into a separate StatefulWidget and then it will work.
You can wrap with StatefulBuilder directly like the following example
String contentText will change after use setState
showDialog(
context: context,
builder: (context) {
String contentText = "Content of Dialog";
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text("Title of Dialog"),
content: Text(contentText),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text("Cancel"),
),
FlatButton(
onPressed: () {
setState(() {
contentText = "Changed Content of Dialog";
});
},
child: Text("Change"),
),
],
);
},
);
},
);