How to add a new button when onPressed is called? - flutter

I have an Elevated Icon Button that when pressed displays a Dialog that prompts a user to enter text and select an amount from a NumberPicker. The showDialog function is called that saves the user's entry in a TextEditingController:
How would I create a function that once the user saves their entry in Dialog, creates a new button that displays TextEditingController.text as shown in the below:
_addItem code:
Future<void> _addItem(BuildContext context) async {
valueText = '';
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Example'),
content: Row(
children: [
Container(
width: 150,
child: TextField(
onChanged: (value) {
setState(() {
valueText = value;
});
},
controller: _textController,
decoration: InputDecoration(hintText: '"Example"'),
),
),
NumberPicker(
value: _currentValue,
minValue: 0,
maxValue: 100,
onChanged: (value) => setState(() => _currentValue = value),
),
],
),
actions: <Widget>[
ElevatedButton(
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
ElevatedButton(
child: Text('OK'),
onPressed: () {
setState(() {
codeDialog = valueText;
Navigator.pop(context);
});
},
),
],
);
});
}
Currently the button updates to the textEditingController.text. I want to replace the Icon with the number selected by the user but I'll figure that out later. Probably best to just replace it with a conditional statement that renders a list of different buttons. They need to be buttons so they can be edited if needed before all data is sent to a server.

You have to use statement in the build method of your Stateful widget
... State of your widget ...
final TextController _textController;
final int _currentValue;
Widget build(context) {
return YourWidgetTree(
child: Row(
children: [
ElevatedButton(child: Text('Add item')),
if(_controller.text.isNotEmpty)
ElevatedButton(child: Text('$_currentValue ${_controller.text}', onPressed: (){ ... })),
])
)
}
Future<void> _addItem(BuildContext context) {...}

Related

TextField (in flutter) getting filled with previously filled values (unintentionally)

On click of floatingActionButton in main.dart file, I'm calling a dialog widget.
main.dart
late ShoppingListDialog dialog;
#override
void initState() {
dialog = ShoppingListDialog();
super.initState();
}
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.add,
),
backgroundColor: Colors.pink,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) => dialog.buildDialog(
context, ShoppingList(id: 0, name: '', priority: 0), true),
);
},
),
shopping_list_dialog.dart
class ShoppingListDialog {
final txtName = TextEditingController();
final txtPriority = TextEditingController();
Widget buildDialog(BuildContext context, ShoppingList list, bool isNew) {
DbHelper helper = DbHelper();
if (!isNew) {
txtName.text = list.name;
txtPriority.text = list.priority.toString();
}
return AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
title: Text((isNew) ? 'New shopping list' : 'Edit shopping list'),
content: SingleChildScrollView(
child: Column(
children: [
TextField(
controller: txtName,
onTap: () {},
decoration: InputDecoration(hintText: 'Shopping List Name')),
TextField(
controller: txtPriority,
keyboardType: TextInputType.number,
decoration:
InputDecoration(hintText: 'Shopping List Priority (1-3)'),
),
TextButton(
child: Text('Save Shopping List'),
onPressed: () {
list.name = txtName.text;
list.priority = int.parse(txtPriority.text);
helper.insertList(list);
Navigator.pop(context);
},
),
],
),
),
);
}
}
TextField is empty, the first time (showing the hint text). But the second time onwards, it gets filled with the last used values, while I intend them to be empty. Like in the image below, the second time when I hit on floatingActionButton to add something, it gets filled with "fruits"(values I had used previously).
TextField should start empty but it's getting filled with previous used values.
Here is a basic solution for you
TextButton(
child: Text('Save Shopping List'),
onPressed: () {
list.name = txtName.text;
list.priority = int.parse(txtPriority.text);
// Clear TE Controller
txtName.clear();
txtPriority.clear();
// Insert
helper.insertList(list);
Navigator.pop(context);
},
),

How to retrieve each element in a List to display as Text in a ElevatedButton?

I have a button that calls a function that adds user input to a List. If the list.isNotEmpty then an ElevatedButton is displayed with the user's input as it's label. I have a numberPicker that allows the user to select an amount, also in the same dialog box. The code works as intended apart from adding the amount to the List (I assume I would need some sort of Map<int, String>?)
I would like to loop through the List and add a new ElevatedButton every time the user enters a new item and amount. So far, the code only creates a new button with the list.first as its text. How do I create a loop to iterate through the List every time the user adds a new item that corresponds with the index to display the correct item?
Code that creates new button:
children: [
ElevatedActionButton(
icon: const Icon(Icons.add),
buttonText: const Text('Add Ingredient'),
onPressedAction: () {
_addIngredient(context);
},
),
if (ingredientList.isNotEmpty)
ElevatedButton(
onPressed: () {},
child: Text(
'$_currentValue ${ingredientList.first}'),
),
],
Code that showsDialog:
Future<void> _addIngredient(BuildContext context) async {
valueText = 'Add Ingredient';
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add Ingredient'),
content: Row(
children: [
Container(
width: 150,
child: TextField(
onChanged: (value) {
setState(() {
valueText = value;
});
},
controller: _ingredientController,
decoration: InputDecoration(hintText: '"Tomato"'),
),
),
NumberPicker(
value: _currentValue,
minValue: 0,
maxValue: 100,
onChanged: (value) => setState(() => _currentValue = value),
),
],
),
actions: <Widget>[
ElevatedButton(
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
ElevatedButton(
child: Text('OK'),
onPressed: () {
setState(() {
if (_ingredientController.text.isNotEmpty) {
ingredientList.add(_ingredientController.text);
codeDialog = valueText;
print(ingredientList);
print(ingredientList.length);
Navigator.pop(context);
} else {
Navigator.pop(context);
}
});
},
),
],
);
});

Flutter : how do i save input from a text field to an int variable?

This is my text controller
final amountController = TextEditingController();
#override
void dispose() {
amountController.dispose();
super.dispose();
}
and when i want to add an item to a list a got an iconbutton that shows a dialog box with a text field where im supposed to get inputs.
IconButton(
icon: Icon(Icons.add),
onPressed: () {
// //this is the part where i add a new income to my list
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Add income'),
content: TextField(
keyboardType: TextInputType.number,
controller: amountController,
onChanged: (s) {
int s = int.parse(amountController.text);
amount = s;
transactions.add(s);
},
),
));
}),
the probleme is that i dont know how to save the data here
List<int> transactions = [];
int amount = 0;
you should not write this line transactions.add(s); in onChanged method, because in this way in each number you enter you add a value to the list.
so you have to assign onChanged value to amount value and add a button to your dialog in button's onPressed method add this line transactions.add(s);
I tried another way :
TextEditingController _textFieldController = TextEditingController();
List<int> transactions = [];
int Total = 0;
Future<void> _displayTextInputDialog(BuildContext context) async {
int Amount = 0;
String valueText = '';
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add income'),
content: TextField(
keyboardType: TextInputType.number,
onChanged: (value) {
setState(() {
valueText = value;
});
},
controller: _textFieldController,
),
actions: <Widget>[
FlatButton(
color: Colors.red,
textColor: Colors.white,
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
FlatButton(
color: Colors.green,
textColor: Colors.white,
child: Text('OK'),
onPressed: () {
setState(() {
Amount = int.parse(valueText);
transactions.add(Amount);
Total = Total + Amount;
print(Amount);
Navigator.pop(context);
});
},
),
],
);
});
}
and i just called the function within a flatbutton

Flutter how to reload entire page

In my application, a user enters data and then it is uploaded to firestore. After this, I would like all the fields to be empty and basically, the entire page reloaded. How do you reload the whole page after an action or button click? I have added the respective stateful classes.
Main Class
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: TestForm(),
),
);
}
}
class TestForm extends StatefulWidget {
#override
_TestFormState createState() => _TestFormState();
}
How to reload this entire form by clicking a button but without going to a new page and being able to go back again.
class _TestFormState extends State<TestForm> {
final _formKey = GlobalKey<FormState>();
File _imageFile;
String locWorking;
Model model = Model();
Future<void> _getLocation() async {
Position position = await Geolocator()
.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
print(position.toString());
setState(() {
model.location = position.toString();
});
}
Future<void> _pickImage(ImageSource source) async {
File selected = await ImagePicker.pickImage(source: source);
setState(() {
_imageFile = selected;
String fileName = 'images/${DateTime.now()}.png';
model.picName = fileName;
model.picCheck = true;
});
}
#override
Widget build(BuildContext context) {
final halfMediaWidth = MediaQuery.of(context).size.width / 2.0;
model.checkBox = false;
return Scaffold(
appBar: AppBar(
title: Text("Form Demo"),
),
body: Form(
key: _formKey,
child: Column(
children: <Widget>[
Container(
alignment: Alignment.topCenter,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
alignment: Alignment.topCenter,
width: halfMediaWidth,
child: MyTextFormField(
hintText: 'Name',
validator: (String value) {
if (value.isEmpty) {
return 'Enter your first name';
}
return null;
},
onSaved: (String value) {
model.firstName = value;
},
),
),
Container(
alignment: Alignment.topCenter,
width: halfMediaWidth,
child: RaisedButton(
color: Colors.blueAccent,
onPressed: () {
_getLocation();
},
child: Text("Get Location")))
],
),
),
MyTextFormField(
hintText: 'Description',
validator: (String value) {
if (value.isEmpty) {
return 'Please Enter Description';
}
return null;
},
onSaved: (String value) {
model.email = value;
},
),
StatefulBuilder(
builder: (context, setState) => CheckboxListTile(
title: Text("Need urgent repair"),
value: model.checkBox,
onChanged: (bool newValue) {
setState(() {
model.checkBox = newValue;
});
},
controlAffinity:
ListTileControlAffinity.leading, // <-- leading Checkbox
),
),
RaisedButton(
color: Colors.blueAccent,
onPressed: () {
if (_formKey.currentState.validate()) {
print(locWorking);
_formKey.currentState.save();
if (model.location == null) {
print("No location");
setState(() {
model.dataCheck = false;
});
print(model.dataCheck);
showDialog(
context: context,
builder: (context) => AlertDialog(
title: new Text("Error"),
content:
new Text("No location has been picked up"),
actions: <Widget>[
new FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: new Text("Close"))
],
));
} else {
print("All checks passed...");
setState(() {
model.dataCheck = true;
});
print(model.dataCheck);
}
if (model.picCheck == false || model.picCheck == null) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: new Text("Notice"),
content: new Text("No picture has been added..."),
actions: <Widget>[
new FlatButton(
onPressed: () {
setState(() {
model.picCheck = true;
model.picName = "Null";
});
Navigator.of(context).pop();
},
child: new Text("No Picture Needed")),
new FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: new Text("Close"))
],
));
}
}
},
child: Text(
'Check Data',
style: TextStyle(
color: Colors.white,
),
),
),
if (_imageFile != null) ...[
Uploader(
file: _imageFile,
fileName: model.picName,
),
],
if (model.dataCheck == true && model.picCheck == true) ...[
DataAdder(model: this.model),
],
],
),
),
bottomNavigationBar: BottomAppBar(
child: Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.photo_camera),
onPressed: () => _pickImage(ImageSource.camera),
),
IconButton(
icon: Icon(Icons.photo_library),
onPressed: () => _pickImage(ImageSource.gallery),
),
],
),
),
);
}
}
Update How to reset the state of the app:
The question wanted to reset the state of the app, not the text field. You can achieve this using the Flutter Phoenix package.
How to reset the TextField input after pressing a button:
setState() rebuilds the build() method in you class every time it's called, but I assume what you mean is you want the text fields to become empty after the user have clicked a button, you could do this by using a TextEditingController.
Declaration:
TextEditingController controller = TextEditingController();
use case:
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
controller: controller,
decoration: InputDecoration(
hintText: "Enter your first name",
),
),
RaisedButton(onPressed: () {
controller.clear();
child:
Text(
"Clear",
);
})
],
),
This should clear the TextField each time the button is pressed.

Flutter showDialog with loading spinner and confirmation

In flutter, I have a showDialog() with cancel and confirm button. The confirm button will trigger a call to an API. What I need is to show a "loading..." in the showDialog window after the click and once the API call is finished to show a success or failure. How can I manage this? Or should I close the window, waiting for the reply and popup a new dialog window with success or false? Thx for any help or better suggestion. Here what I have so far:
void _showAlert(String textLabel, String action, String linkId) {
showDialog(
context: context,
//barrierDismissible: false, // on external click
builder: (_) => new AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
title: new Text(
'Please confirm:',
style: TextStyle(color: Colors.deepOrange, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
content: new Text(
textLabel,
style: new TextStyle(fontSize: 20.0),
),
actions: <Widget>[
new FlatButton(
onPressed: () {
Navigator.pop(context);
},
child: new Text('CANCEL')),
new FlatButton(
onPressed: () {
_postAction(action, linkId).then((_) => setState(() {}));
Navigator.pop(context);
},
child: new Text('I CONFIRM')),
],
));
}
You can try this,this is just the idea..
class _SampleState extends State<Sample> {
bool isSuccessFromApi = false;
bool isLoading = false;
Widget popup() {
showDialog(context: context, builder: (builder) {
return AlertDialog(
content: !isSuccessFromApi ? Container(
child: Text('Are you Sure???'),
) : Container( child: isLoading ? CircularProgressIndicator() : Text('Success'),),
actions: <Widget>[
Text('Cancel'),
InkWell(child: Text('OK'), onTap: apiCall,)
],
);
});
}
void apiCall(){
setState(() {
isLoading = true;
});
//call the api
//after success or failure
setState(() {
isLoading = false;
isSuccessFromApi = true;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: popup(),
);
}
}