Page refreshes when textformfield is focused on - flutter

In a 'Edit Profile' page, when a Textformfield is focused on to edit the text, the entire page reloads and doesn't allow me to change or input anything. The code is like this :
body: Form(
key: _formKey,
child: FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
future: FirebaseFirestore.instance
.collection('appusers')
.doc(widget.id)
.get(),
builder: (_, snapshot) {
if (snapshot.hasError) {
print('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
var data = snapshot.data!.data();
var name = data!['name'];
return Padding(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 30),
child: Column(
children: [
Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: TextFormField(
initialValue: name,
autofocus: false,
onChanged: (value) => name = value,
decoration: InputDecoration(
labelText: 'Name: ',
border: OutlineInputBorder(),
errorStyle:
TextStyle(color: Colors.redAccent, fontSize: 12),
),
validator: (value) {
RegExp regex = new RegExp(r'^.{3,}$');
if (value == null || value.isEmpty) {
return 'Please enter full name.';
}
if (!regex.hasMatch(value)) {
return ("Please enter a name.");
}
return null;
},
),
),
SizedBox(height: 40),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
updateUser(widget.id, name);
}
Navigator.of(context).pop();
},
child: Text(
'Update',
style: TextStyle(fontSize: 15),
),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(
'Cancel',
style: TextStyle(fontSize: 15),
),
),
],
),
)
],
),
);
},
)),
Is there a reason why the page keeps being refreshed? There are other textfields similar to 'name' and clicking on any of those causes this page to reload. The formkey has been declared before Widget build as final _formKey = GlobalKey<FormState>();.

To give you an understanding of how flutter handles the app when the keyboard is opened.
When the keyboard is opened, flutter actually changes the screen size (i.e the bottom padding changes) because of this when you access the MediaQuery.of(context) in this widget it will cause the widget to rebuild so that MediaQuery.of(context) will return the updated MediaQueryData. This rebuilding is fine.
The problem is in the way you are using the FutureBuilder s future parameter. The FirebaseFirestore.instance.collection('appusers').doc(widget.id).get() will get executed everytime there is a rebuild of this EditProfile widget , but you probably want this to be called only once when the widget is loaded first time. So you need to initialize the future in the StatefulWidget initState like:
Future future;
#override
void initState() {
super.initState();
future = FirebaseFirestore.instance.collection('appusers').doc(widget.id).get();
}
Now this will not call the FirebaseFirestore call whenever the widget rebuilds. But there is another issue with your TextFormFields initialValue parameter. It uses the name variable which is declared and being initialized within the build method which does not seem right. You could do something like:
var name:
Future future;
#override
void initState() {
super.initState();
future = FirebaseFirestore.instance.collection('appusers').doc(widget.id).get();
future.then((value) {
if(value != null) {
var name = value.data!['name'];
}
});
}

Related

Flutter: Form Validation not checking for null input, "undefined name _formKey"

This is my current code. The "Field required" does not show up when the input is null.
class _HomeState extends State<Home> {
final _formkey = GlobalKey<FormState>();
final FocusNode _nameFocusNode = FocusNode();
final TextEditingController _nameController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
//padding: const EdgeInsets.all(15.0),
key: _formkey,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0)
),
),
),
TextFormField(
keyboardType: TextInputType.name,
textInputAction: TextInputAction.next,
focusNode: _nameFocusNode,
onFieldSubmitted: (String value) {
_nextFocus(_addressFocusNode);
},
controller: _nameController,
validator: (value) {
if (value == null || value.isEmpty) {
return 'Field required';
}
return null;
},
And this is the submit button code:
ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.deepOrange),
),
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: SingleChildScrollView(
child: ListBody(
children: [
Text(
'Name:',
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(_nameController.text),
),
onPressed: () => Navigator.pop(context, 'Confirm'),
child: const Text('Confirm'),
),
],
)),
);
},
);
},
child: Text('Submit'),
),
Furthermore, according to flutter docs (https://docs.flutter.dev/cookbook/forms/validation), I'm sure I have to insert this portion of code on my submit button but I can't find the right way to integrate it.
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState!.validate()) {
}
I've inserted the
if (_formKey.currentState!.validate())
after "onPressed" and before "showDialog" but I get the error "Undefined name '_formKey'"
You need to wrap your widget with a Form and pass your key to that widget (because you want a FormState from that GloabaaKey)
return Form(
key: _formKey,
child: Scaffold(...),
);
That way your GlobalKey will actually reference a FormState and you can pass that to any onPressed method
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState!.validate()) {
showDialod(...);
} else {
/// show error message or do something
}

Deleting specific item out of ListView with Bloc

I have a page that consists of a ListView, which contains TextFormFields. The user can add or remove items from that ListView.
I use the bloc pattern, and bind the number of Items and their content inside the ListView to a list saved in the bloc state. When I want to remove the items, I remove the corresponding text from this list and yield the new state. However, this will always remove the last item, instead of the item that's supposed to be removed. While debugging, I can clearly see that the Item I want removed is in fact removed from the state's list. Still, the ListView removes the last item instead.
I've read that using keys solves this problem and it does. However, if I use keys there is a new problem.
Now, the TextFormField will go out of focus every time a character is written. I guess this is to do with the fact that the ListView is redrawing its items everytime a character is typed, and somehow having a key makes the focus behave differently.
Any ideas how to solve this?
The page code (The ListView is at the bottom):
class GiveBeneftis extends StatelessWidget {
#override
Widget build(BuildContext context) {
var bloc = BlocProvider.of<CreateChallengeBloc>(context);
return BlocBuilder<CreateChallengeBloc, CreateChallengeState>(
builder: (context, state) {
return CreatePageTemplate(
progress: state.progressOfCreation,
buttonBar: NavigationButtons(
onPressPrevious: () {
bloc.add(ProgressOfCreationChanged(nav_direction: -1));
Navigator.of(context).pop();
},
onPressNext: () {
bloc.add(ProgressOfCreationChanged(nav_direction: 1));
Navigator.of(context).pushNamed("create_challenge/add_pictures");
},
previous: 'Details',
next: 'Picture',
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'List the benefits of you Challenge',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
SizedBox(height: 30),
Text(
'Optionally: Make a list of physical and mental benefits the participants can expect. ',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.grey,
fontSize: 14,
fontWeight: FontWeight.w400),
),
SizedBox(height: 50),
Container(
margin: EdgeInsets.all(8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.yellow[600]),
child: FlatButton(
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onPressed: () => bloc.add(ChallengeBenefitAdded()),
child: Text('Add a benefit',
style: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold)),
),
),
Expanded(
child: new ListView.builder(
itemCount: state.benefits.length,
itemBuilder: (BuildContext context, int i) {
final item = state.benefits[i];
return Padding(
padding: EdgeInsets.symmetric(horizontal: 25),
child: TextFieldTile(
//key: UniqueKey(),
labelText: 'Benefit ${i + 1}',
validator: null,
initialText: state.benefits[i],
onTextChanged: (value) => bloc.add(
ChallengeBenefitChanged(
number: i, text: value)),
onCancelIconClicked: () {
bloc.add(ChallengeBenefitRemoved(number: i));
},
));
})),
],
),
);
});
}
}
The Code of the TextfieldTile:
class TextFieldTile extends StatelessWidget {
final Function onTextChanged;
final Function onCancelIconClicked;
final Function validator;
final String labelText;
final String initialText;
const TextFieldTile(
{Key key,
this.onTextChanged,
this.onCancelIconClicked,
this.labelText,
this.initialText,
this.validator})
: super(key: key);
#override
Widget build(BuildContext context) {
return Stack(children: <Widget>[
TextFormField(
textCapitalization: TextCapitalization.sentences,
initialValue: initialText,
validator: validator,
onChanged: onTextChanged,
maxLines: null,
decoration: InputDecoration(
labelText: labelText,
)),
Align(
alignment: Alignment.topRight,
child: IconButton(
icon: Icon(Icons.cancel), onPressed: onCancelIconClicked),
),
]);
}
}
The relevant portion of the Bloc:
if (event is ChallengeBenefitAdded) {
var newBenefitsList = List<String>.from(state.benefits);
newBenefitsList.add("");
yield state.copyWith(benefits: newBenefitsList);
}
else if (event is ChallengeBenefitChanged) {
var newBenefitsList = List<String>.from(state.benefits);
newBenefitsList[event.number] = event.text;
yield state.copyWith(benefits: newBenefitsList);
}
else if (event is ChallengeBenefitRemoved) {
var newBenefitsList = List<String>.from(state.benefits);
newBenefitsList.removeAt(event.number);
yield state.copyWith(benefits: newBenefitsList);
}
I can think of two things you can do here.
Create a different bloc for processing the changes in the text field, that will avoid having to actually update the state of the entire list if no needed.
Have a conditional to avoid rebuilding the list when your bloc change to a state that is relevant only to the keyboard actions.
Example:
BlocBuilder<CreateChallengeBloc, CreateChallengeState>(
buildWhen: (previousState, currentState) {
return (currentState is YourNonKeyboardStates);
}
...
);

Enable Button on flutter only if Checkbox is " checked"

Hello guys I have registration form with checkbox to be enabled in order to allow registration.
I need my user to do checkbox checked to have button enabled otherwise an tooltip will be shown.. like... " u need to accept terms and condition to register... "
This is the part of the CheckBox:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Theme(
data: ThemeData(unselectedWidgetColor: Colors.white,),
child: Checkbox(
focusColor: Colors.lightBlue,
activeColor: Colors.orange,
value: rememberMe,
onChanged: (newValue) {
setState(() {
rememberMe = (newValue);
});
},
),
),
RichText(
text: TextSpan(children: [
TextSpan(
text: 'Accetto le condizioni e ',
style: TextStyle(fontSize: 10),
),
TextSpan(
text: 'il trattamento dei dati personali ',
style: TextStyle(fontSize: 10,decoration: TextDecoration.underline,),
),
]),
)
],
),
and this the "registration Button"
ButtonTheme(
minWidth: 100,
height: 50.0,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
elevation: 10,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
final newUser =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}
setState(() {
showSpinner = false;
});
} catch (e) {
print(e);
}
},
color: Color(0xFF1f2032),
child: Text(
'SIGNUP',
style: TextStyle(fontSize: 18, color: Colors.white),
),
),
),
There are certain things which I would like to give you an insight about. Which will help you surely, so follow along.
Pointers
Read upon Flutter Form and it's Validation, which answers your question on showing up the error message under your forms for the validations
One very useful widget to achieve what you want is Flutter Tooltip Unfortunately, you cannot bring up the tooltip which you wanted to do programmatically
Workaround: Do use any of these to show up you message
Snackbar Flutter
Flutter AlerDialog
Simply show up a text, like a validator for the form under the checkbox like I will demonstrate in the code for you
Now, I have demonstrated both of them in this code, but the code is not similar. It would be enough to you let you know the best practices you can do along with your tooltip message showcase
Please note: To make a tooltip like structure using Container(), you can follow this answer, will help you in a great extent
class _MyHomePageState extends State<MyHomePage> {
bool rememberMe = false;
// this bool will check rememberMe is checked
bool showErrorMessage = false;
//for form Validation
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: TextFormField(
validator: (value) {
// retiurning the validator message here
return value.isEmpty ? "Please enter the message" : null;
}
)
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Accept Terms & Conditions'),
SizedBox(width: 20.0),
Checkbox(
focusColor: Colors.lightBlue,
activeColor: Colors.orange,
value: rememberMe,
onChanged: (newValue) {
setState(() => rememberMe = newValue);
}
)
]
),
// based up on this bool value
showErrorMessage ?
Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(80.0)
),
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text('Please accept the terms and conditions to proceed...')
)
)
: Container(),
SizedBox(height: 20.0),
RaisedButton(
child: Text('Submit'),
onPressed: (){
// for your form validation
if(_formKey.currentState.validate()){
// do your success operation here!
// checking for the rememberValue
// and setting the message bool data
if(rememberMe != true)
setState(() => showErrorMessage = true);
else
setState(() => showErrorMessage = false);
}
}
)
]
)
)
);
}
}
How it works?
It will first check whether the form is empty, if it not, then checks whether the checkbox is empty or not
Fun Fact
You can use the above logic or bool showErrorMessage, to show anything, be it, SnackBar, AlertDialog or the message which I showed in the above code.
Result
You need to pass null to the onPressed of a Button to make it disabled. So you'll need to pass null to the onPressed of the RaisedButton when rememberMe is false.
ButtonTheme(
minWidth: 100,
height: 50.0,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
elevation: 10,
onPressed: rememberMe ? () async {
setState(() {
showSpinner = true;
});
try {
final newUser =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}
setState(() {
showSpinner = false;
});
} catch (e) {
print(e);
}
} : null, // make it null if false
color: Color(0xFF1f2032),
child: Text(
'SIGNUP',
style: TextStyle(fontSize: 18, color: Colors.white),
),
),
),

How to start something automatically in flutter

I have the following code that initially displays a blank page, but I'd like an rAlert dialog to display automatically. Once the user clicks 'Request' or 'Cancel', some text will be displayed on the screen.
But I can't get the code to run that displays the Alert. I had it working by showing a button and clicking the button, but i need the Alert to display automatically when the page is displayed. I tried putting it in the initState. I didn't get any errors, but it didn't work either.
Anyone know what I need to do? Thanks?
import 'package:flutter/material.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'dart:async';
import 'package:rostermeon/cwidgets/general_widgets.dart';
import 'package:rostermeon/rmo_constants.dart';
class ForgotPassword extends StatefulWidget {
static const String id = 'forgot_password_screen';
#override
_ForgotPasswordState createState() => _ForgotPasswordState();
}
class _ForgotPasswordState extends State<ForgotPassword> {
StreamController<bool> _events;
#override
initState() {
super.initState();
_events = new StreamController<bool>();
doRequest(context: context);
}
Future<bool> doSaveRequest({String pReason}) async {
await Future.delayed(const Duration(seconds: 3), () {});
return false;
}
Future<bool> doRequest({context}) {
String _reason = '';
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
TextEditingController reasonController = TextEditingController();
TextStyle _style = TextStyle(fontFamily: 'Montserrat', fontSize: 18.0, fontWeight: FontWeight.normal);
InputDecoration _textFormFieldDecoration({String hintText, double padding}) => InputDecoration(
//contentPadding: EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 8.0),
contentPadding: EdgeInsets.all(padding),
isDense: true,
hintText: hintText,
hintStyle: TextStyle(color: kHintText),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),
);
return Alert(
context: context,
title: 'Request New Password',
content: StreamBuilder<bool>(
initialData: false,
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
print(" ${snapshot.data.toString()}");
return snapshot.data
? CircularProgressIndicator()
: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 20.0),
Text('Email', textAlign: TextAlign.left, style: _style),
SizedBox(height: 10.0),
TextFormField(
validator: (value) {
if (value.isEmpty) {
return "please enter email";
}
return null;
},
onSaved: (value) {
_reason = value;
},
decoration: _textFormFieldDecoration(
hintText: 'your email address',
padding: 8.0,
),
controller: reasonController,
),
SizedBox(height: 10.0),
],
),
);
}),
buttons: [
DialogButton(
child: Text('Request', style: TextStyle(color: Colors.white, fontSize: 20)),
color: kMainColor,
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print(_reason);
_events.add(true);
var saved = await doSaveRequest(pReason: _reason);
if (saved) {
Navigator.pop(context, false);
} else {
_events.add(false);
}
Navigator.of(context).pop();
// Navigator.pop(context, false);
}
},
),
DialogButton(
child: Text('Cancel', style: TextStyle(color: Colors.white, fontSize: 20)),
color: kMainColor,
onPressed: () {
Navigator.pop(context, false);
},
),
],
).show();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: rmoAppBar(subText: 'Request New Password', hideBackButton: false),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[],
),
),
);
}
}
Dialogs/Alerts need the buildContext in order to work, You can't have the buildContext before build() method is called, that's why you can't just call it in initstate() before the build is called.
To make it work use addPostFrameCallback to make sure it delays until widget is built:
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => yourMethod(context));
}
https://www.didierboelens.com/2019/04/addpostframecallback/

How to pass data from alertdialog to page in flutter?

I am passing data from my alertdialog to item of listview.
Where I can find information about it?
I tried use TextEditingController, with Navigation Routes. And I used materials from this Tutorial
This is my code:
class MeasurementsScreen extends StatefulWidget {
#override
_MeasurementsScreenState createState() => _MeasurementsScreenState();
}
class _MeasurementsScreenState extends State<MeasurementsScreen> {
List<_ListItem> listItems;
String lastSelectedValue;
var name = ["Рост", "Вес"];
var indication = ["Введите ваш рост", "Введите ваш вес"];
TextEditingController customcintroller;
void navigationPageProgrammTrainingHandler() {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => ProgrammTrainingHandler()),
);
}
#override
void initState() {
super.initState();
initListItems();
}
Future<String> createAlertDialog(BuildContext context, int indexAl){
customcintroller = TextEditingController();
if(indexAl < 2){
return showDialog(context: context, builder: (context){
return AlertDialog(
title: Text(name[indexAl]),
content: TextField(
textDirection: TextDirection.ltr,
controller: customcintroller,
style: TextStyle(
color: Colors.lightGreen[400],
fontSize: 18.5),
decoration: InputDecoration(
contentPadding: EdgeInsets.only(bottom: 4.0),
labelText: indication[indexAl],
alignLabelWithHint: false,
),
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.done,
),
actions: <Widget>[
FlatButton(
child: const Text('ОТМЕНА'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: const Text('ОК'),
onPressed: () {
Navigator.of(context).pop(customcintroller.text.toString());
},
),
],
);
});
} else if (indexAl > 1){
navigationPageProgrammTrainingHandler();
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Color(0xff2b2b2b),
appBar: AppBar(
title: Text(
'Замеры',
style: new TextStyle(
color: Colors.white,
),),
leading: IconButton(
icon:Icon(Icons.arrow_back),
color: Colors.white ,
onPressed:() => Navigator.of(context).pop(),
),
),
body: ListView.builder(
physics: BouncingScrollPhysics(),
itemCount: listItems.length,
itemBuilder: (BuildContext ctxt, int index){
return GestureDetector(
child: listItems[index],
onTap: () {
createAlertDialog(context, index).then((onValue){
});
}
);
},
),
);
}
void initListItems() {
listItems = [
new _ListItem(
bgName: 'assets/images/soso_growth.jpg',
name: customcintroller.text.toString().isEmpty == false ? customcintroller.text.toString() : "Рост",
detail: "Нажми, чтобы добавить свой рост"),
new _ListItem(
bgName: 'assets/images/soso_weight.jpg',
name: customcintroller.text.toString().isEmpty == false ? customcintroller.text.toString() : "Вес",
detail: "Нажми, чтобы добавить свой вес"),
new _ListItem(
bgName: 'assets/images/soso_chest.jpg',
name: "Грудь",
detail: "PRO-версия"),
new _ListItem(
bgName: 'assets/images/soso_shoulder.jpg',
name: "Плечи",
detail: "PRO-версия"),
new _ListItem(
bgName: 'assets/images/soso_biceps.jpg',
name: "Бицепс",
detail: "PRO-версия")
];
}
}
class _ListItem extends StatelessWidget {
_ListItem({this.bgName, this.name, this.detail});
// final int index;
final String bgName;
final String name;
final String detail;
#override
Widget build(BuildContext context) {
return Container(
height: 180.0,
margin: const EdgeInsets.symmetric(
vertical: 1.0,
),
child: new Stack(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage(bgName),
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.45), BlendMode.darken),
fit: BoxFit.cover,
alignment: Alignment.center),
),
child: new SizedBox.expand(
child: Container(
alignment: Alignment.center,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
name,
style: new TextStyle(fontSize: 29.0, color: Colors.white),
),
Padding(
padding: const EdgeInsets.only(top: 12.0),
child: new Text(
detail,
style:
new TextStyle(fontSize: 16.0, color: Colors.white),
),
)
],
),
),
),
),
],
),
);
}
}
I expect to get text from alertdialog.
Do you want to update data in your current screen or in another Scaffold/screen? Solution for the first option would be to set your desired data in a setState or pass it to a Model (with ScopedModel) and update the view. E.g. :
FlatButton(
child: const Text('ОТМЕНА'),
onPressed: () {
setState(() {
myData = data;
Navigator.of(context).pop();
}); // not sure if this will work, could you try?
}
),
If it is in a new/other screen, you can pass it in the Navigator like for example:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewScreen(data: myData),
),
);
},
Does this solve your problem? Otherwise, please elaborate on what it is you need.
I tried to use Navigator.of(context).pop("OK"); in the AlertDialog but it doesn't work.
use ValueChanged as a param on the showDialog method and it works well.
class Dialogs{
static showAlertDialog(BuildContext context, String title, String message,
{List<String> actions, ValueChanged onChanged}) async {
if (actions == null) {
actions = ["OK"];//default OK button.
}
await showDialog(
context: context,
child: AlertDialog(
title: Text(title ?? 'Message'),
content: Text(message),
actions: actions
.map((e) => new FlatButton(
child: Text(e.trim()),
onPressed: () {
Navigator.of(context).pop(e.trim());
if (onChanged != null) {
onChanged(e.trim());
}
}))
.toList(),
),
);
}
}
the caller looks like
_onProcess(){
String result = "";
await Dialogs.showAlertDialog(context, "Warning", "Warning message", actions: ["OK", "Cancel"],
onChanged: (value) {
result = value;
});
if (result != "OK") {
Dialogs.showSnackBarMessage(context, "Cancel This PTN");
return;
}
....process with the OK logic.
}
If you want to change an item of the list you can do that with setState() before calling Navigator.pop(). It is not possible to pass data through Navigator.pop() though, as you may be able to do with Navigator.push(... MyPage(data)).
You could achieve what you want through State management. You can check for state management tutorials in general. But the two practices that are used most in my opinion are Scoped Model and BLoC pattern. These practices help you pass data through the widget tree back and forward. I would recommend BLoC pattern there are many tutorials about it. Also there is a package which can be very helpful with BLoC pattern: flutter_bloc.