Counter Inside AlertDialog - Flutter - flutter

I am using an AlertDialog for my application and inside i build an counter. Value of counter does not get updated automatically. i used "setState({})", but it does not help, because it only rebuilds the build() function and not the int _value inside Dialog.
Anyone familiar to this problem and help me out?
Thank you

The code sample below solved my problem. As #anmol.majhail nicely referred, a wrote my AlertDialog inside a new class, which was then called by the build() function. To call the class and show AlertDialog i used to do this.
Widget createItem() {
return new FloatingActionButton(
elevation: 4.0,
child: const Icon(Icons.create),
onPressed: () {
showDialog(
context: context,
child: new ItemAlertView()
);
},
);
}
This example helped me out (compare to line 59). https://gist.github.com/harshapulikollu/5461844368e95c6d3a38fffe72f03eee

User StatefulBuilder to return AlertDialog.
showDialog(
context: context,
builder: (context) {
String contentText = "Initial Content";
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
title: Text("Title Here"),
content: Text(contentText),
actions: <Widget>[
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text("Cancel"),
),
FlatButton(
onPressed: () {
setState(() {
contentText = "Changed!";
});
},
child: Text("Change Now"),
),
],
);
},
);
},
);

Cleanest way, in my opinion, would be to use a Stream with a StreamBuilder.

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 enable/disable dialog buttons (actions)

I have a helper function to create dialogs in my flutter app:
Future<void> showContentDialog(BuildContext context,
{required Widget content, String? title, List<Tuple2<String, void Function()>>? actions}) async {
Widget? titleWidget;
if (title != null) {
titleWidget = Text(
title,
style: Theme.of(context).textTheme.titleSmall!.copyWith(fontWeight: FontWeight.bold),
);
}
var dialogActions = <Widget>[];
if (actions != null) {
dialogActions.addAll(
actions.map(
(a) => TextButton(
child: Text(a.item1),
onPressed: () {
a.item2();
}),
),
);
}
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
title: titleWidget,
content: SizedBox(width: ThemeHelpers.maxPopupWidth, child: content),
actions: dialogActions,
),
);
}
There is another similar one that is used on Apple devices that uses equivalent widgets.
I can easyly manage state on the content portion of the dialog by wrapping it in a StatefulBuilder, but how can I enable and disable the dialog buttons (the actions passed to the AlertDialog) builder depending on content state?
My first idea was to add another a ValueNotifier parameter to the action builders and wrap them in ValueListenerBuilders but that didn't work.
Do I have any way of doing that other than including the actions as buttons inside the content (were I can easyly manage their state)?
You can pass null on onPressed to disable the button state. While it is not clear from where you like to controll the state, you can use ValueNotifier, and it work for all widget
final ValueNotifier<bool> enableButton = ValueNotifier(false);
Future<void> showContentDialog(
BuildContext context,
) async {
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
content: SizedBox(
width: 222,
child: Column(
children: [
Text("A"),
ElevatedButton(
onPressed: () {
enableButton.value = !enableButton.value;
},
child: Text("toggleButtonState"),
)
],
),
),
actions: [
ValueListenableBuilder<bool>(
valueListenable: enableButton,
builder: (context, value, child) => ElevatedButton(
onPressed: value ? () {} : null,
child: Text("BTN"),
),
),
],
),
);
}
In content add column and add dialog widgets in it
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) => AlertDialog(
title: titleWidget,
content: Column(
mainAxisSize: MainAxisSize.min,
children : [
SizedBox(width: ThemeHelpers.maxPopupWidth, child: content),
dialogActions,
]
)
),
);

Values in RangeSlider inside AlertDialog not updating

I cannot understand why my rangeslider is not updating values when dragging. I am supposed to update the state with the onChanged function, but nothing seems to work. It only works when I press the "Apply" button and I reopen my alertDialog again, where I see the values of the slider updated. All this is wrapped inside and Appbar in a statefulWidget. When I press the filter button a pop up appears with the filter.
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Filter'),
content: SizedBox(
child: Card(
child: Column(
children: [
Text('Age'),
RangeSlider(
values: _rangeValues,
divisions: 20,
labels: RangeLabels(
_rangeValues.start.round().toString(),
_rangeValues.end.round().toString()),
onChanged: ( value ) {
_rangeValues = value ;
setState(() {
isFiltering = false;
varSelectedFilterAgeStart = value.start;
varSelectedFilterAgeEnd = value.end;
});
},
min: 0.0,
max: 20.0,
),
],
),
),
),
actions: [
ElevatedButton(
child: const Text('Apply'),
onPressed: () {
setState(() {
isFiltering = true;
varSelectedFilterAge = varSelectedFilterAgeStart;
});
Navigator.of(context).pop(varSelectedFilterAge);
},
),
ElevatedButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
What am I doing wrong??
Wrap your AlertDialog with StatefulBuilder and use its setState.
showDialog(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (context, setState) => AlertDialog(

How to make Alert Dialog working in 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();
},
)
],
);
};
);

Flutter prevent close dialog on back pressed

I am using the showDialog function to build a dialog box, but I need to avoid that when the user presses the back button, the dialog box does not close, this is my code:
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: new Text("Hello"),
content: new SingleChildScrollView(
child: Container(),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("Close"),
onPressed: () {
},
),
],
);
},
);
How can I get it to not close?
You need to enclose your AlertDialon on a WillPopScope like this:
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return WillPopScope(
onWillPop: (){},
child:AlertDialog(
title: new Text("Hello"),
content: new SingleChildScrollView(
child: Container(),),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("Close"),
onPressed: () {
},
),
],
)
)
},
);
The WillPopScope provides you a onWillPop parameter, where you can pass a function of what you want when the child pop. In this case, the parameter receive an empty function so it wont pop.
You need to use a WillPopScope. It will use the function on onWillPop to determine if the dialog closes or not. In this case always false, so the user can't use the back button to close the dialog.
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return WillPopScope(
child: AlertDialog(
title: new Text("Hello"),
content: new SingleChildScrollView(
child: Container(),
),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
onWillPop: () async {
return false;
},
);
},
);
You can also do it by setting onWillPop: () => Future.value(false) inside WillPopScope. Right now onWillPop:(){} as mentioned in Accepted answer gives warning.
Warning Message: This function has a return type of 'Future', but doesn't end with a return statement.
Try adding a return statement, or changing the return type to 'void'.
So, use onWillPop: () => Future.value(false) or onWillPop: () async {return false;}, instead.
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return WillPopScope(
child: AlertDialog(
................
),
onWillPop: () => Future.value(false),
);
},
);
If you are using Getx Dialog then use like this:
Get.defaultDialog(
titlePadding: EdgeInsets.all(0),
title: "",
barrierDismissible: false,
radius: 10,
onWillPop: () => Future.value(false),
content:Container());