flutter reset form key when with Navigator context change - forms

New to flutter, so maybe quoting the question in a misleading way. Please correct if so.
I have a flutter form that I want to reset when a button (not the InkWell) is pressed. Something like this
Form(
key: formKey,
child: Column(
children: <Widget>[
TextFormField( ),
SizedBox(height: 15),
TextFormField( ),
SizedBox(height: 15),
DateTimePicker( ),
SizedBox(height: 15),
InkWell(
onTap: () {
// navigate to another page, leaving the form as it is,
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SharePage( ),
),
);
}
},
child: Container(...)
),
TextButton(
child : Text('Reset Form'),
onpressed : (){
//doesn't reset the form when the InkWell above is used to navigate to another page and back
formKey.currentState.reset()
}
)
],
),
),
It works normally when the formKey.currentState.reset is called. But when I press the InkWell to go to the SharePage and come back from there, the reset method of the formKey.currentState doesn't resets the form to its initial state, instead it resets the form to the state it was just before going to the SharePage. How do I reset the form to the complete initial state even after coming from the SharePage?

did you try to update
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SharePage( ),
),
);
}
},
child: Container(...)
),
to be like so,
InkWell(
onTap: () {
/// add following line
formKey.reset
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SharePage( ),
),
);
}
},
child: Container(...)
),
--UPDATE--
to use resetting functionality from anywhere on the screen
TextButton(
child : Text('Reset Form'),
onPressed: () {
formKey.currentState.reset();
},)

Related

How to hide or show an icon in a row in Flutter

I have a row which includes 3 icons, but one of them needs to be shown if notes have been added, but hidden if there are no notes.
I tried to use Visibility but couldn't get it right. If there are no notes, I need to use a SizedBox() so everything else stays aligned correctly.
What's the right way to do this?
Expanded(
flex: 14,
child: Center(
child: GestureDetector(
onTap: () {
print(data[index].rosterId);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ShiftsForRoster(
rId: data[index].rosterId,
),
),
);
},
child: Icon(Icons.note_alt_outlined, size: 35, color: kMainColor80),
),
),
),
I can't see in your code snippet, how you check if you have notes or not. I used a bool "notestExist", check if it's true and show your icon, else show an empty Container. You could also do something like notes.length != 0
Expanded(
flex: 14,
child: notesExist ? Center(
child: GestureDetector(
onTap: () {
print(data[index].rosterId);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ShiftsForRoster(
rId: data[index].rosterId,
),
),
);
},
child: Icon(Icons.note_alt_outlined, size: 35, color: kMainColor80),
),
) : Contaniner()
),

Flutter show dialog show only if 2 showDialog() is called in one function

I have a showDialog() function in flutter web, but it will only works this way (2 show dialog in one function), if I comment out the other one, the dialog will not show. I don't really understand why I need to put 2 showDialog() in order for it to show up. Here is the code:
onDeleteTap(String id) async {
print(id);
await showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Hapus?'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
],
),
),
actions: <Widget>[
TextButton(
child: Text('Batal'),
onPressed: () {
},
),
SizedBox(
width: 150.0,
child: ErrorButton(
text: "Hapus",
onClick: () {
},
),
),
],
);
},
);
await showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Hapus?'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
],
),
),
actions: <Widget>[
TextButton(
child: Text('Batal'),
onPressed: () {
},
),
SizedBox(
width: 150.0,
child: ErrorButton(
text: "Hapus",
onClick: () {
},
),
),
],
);
},
);
I think before you are calling onDeleteTap you must be using navigator.pop(context). You can check by not showing any dialog to check if you are really poping a screen (If you are having a pop your current screen will close or you will have a black screen) or you can use the debbuger to check all the lines that passes before getting to this code.

Flutter application Navigation Issue

There are 2 screens in my application. In first screen I am listing all data from my sqflite database. In second screen I am giving functionality to delete that record. But when I pop that screen from the stack. It should be refreshed. How can I achieve that.
This is my first screen return code.
return FutureBuilder<List>(
future: DatabaseHelper.instance.queryAll(),
initialData: List(),
builder: (context, snapshot) {
return snapshot.hasData
? new ListView.builder(
padding: const EdgeInsets.all(10.0),
itemCount: snapshot.data.length,
itemBuilder: (context, i) {
print("value : " + snapshot.data.toString());
return new Card(
child: Column(mainAxisSize: MainAxisSize.min, children: <
Widget>[
ListTile(
leading:
Image.file(File(snapshot.data[i]["thumbnail_url"])),
title: Text(
snapshot.data[i]["title"],
style: _biggerFont,
),
subtitle: Text(snapshot.data[i]["month"] +
", " +
snapshot.data[i]["year"]),
onTap: () {
},
),
ButtonBar(
children: <Widget>[
Visibility(
visible: _isUrduAvail,
child: FlatButton(
child: const Text('اردو'),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => OfflinePdfViewer(
snapshot.data[i]["id"].toString(),
snapshot.data[i]["title"],
snapshot.data[i]["urdu_url"],
"Urdu")));
},
),
),
Visibility(
visible: _isEnglishAvail,
child: FlatButton(
child: const Text('English'),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => OfflinePdfViewer(
snapshot.data[i]["id"].toString(),
snapshot.data[i]["title"],
snapshot.data[i]["english_url"],
"English")));
},
),
),
Visibility(
visible: _isHindiAvail,
child: FlatButton(
child: const Text('हिन्दी'),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => OfflinePdfViewer(
snapshot.data[i]["id"].toString(),
snapshot.data[i]["title"],
snapshot.data[i]["hindi_url"],
"Hindi")));
},
),
),
],
)
]));
},
)
: Center(
child: CircularProgressIndicator(),
);
},
);
In this screen i am building the list and populate the FutureBuilder.
and in second screen I have button on that button click the record will be deleted but what will be the route to call that it can be refreshed?
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) => LibraryScreen(),
),
(route) => false,
);
I have tried this code but it clear all my activity stack.
When you call second screen try to use 'pushReplacement' instead of 'push'
If you pushAndRemoveUntil you cannot go back to the same page. You need to push it again in which case the FutureBuilder will rebuild and you will see the correct data.
Or a better solution would be to get your data as a Stream instead of a Future and use StreamBuilder instead of FutureBuilder.
You can try to use 'Pushreplacement' because it will dispose the previous route.

How to pass a variable reference between different routes?

Im writing a simple gamebook game in flutter with menu, game and options route. In option route there is button that on pressed should delete all saved games.
Right at this moment Im loading saved games on application launch from SharedPreferences. Right after loading them I set up boolean _savedGame that im using in 'Continue' button in menu route and 'Delete saved games' button in options route to activate or deactivate them. The whole problem is - i dont know how to change variables in menu route from option route. When im creating option route I give it _savedGame so that it knows if it should render active or deactivated button.
PS. Yes, I know that right now im sending option route a copy of _savedGame variable.
Menu route option page button.
RaisedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OptionsPage(_savedGame),
),
),
Option page
class OptionsPageState extends State<OptionsPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Options",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.blueGrey[900],
),
body: Container(
alignment: Alignment.center,
color: Colors.cyan,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child:
Text('Delete saved games', style: TextStyle(fontSize: 40)),
onPressed:
widget.isGameSaved ? () => _showWarning(context) : null,
),
const SizedBox(height: 30),
RaisedButton(
child: Text('Back', style: TextStyle(fontSize: 40)),
onPressed: () {
Navigator.pop(context);
},
),
])),
),
);
}
Future<void> _showWarning(BuildContext context) {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Are you sure you want to delete saved game?'),
actions: <Widget>[
FlatButton(
child: Text('No'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('Yes'),
onPressed: () {
saveGame('empty');
Navigator.of(context).pop();
setState(() {
widget.isGameSaved = false;
});
},
),
],
);
},
);
}
}
How do I "setState" for variables in different routes?
What you could do is have an InheritedWidget (call it say GameStateWidget) above your Navigator (or MaterialApp if you're using its navigator). In the InheritedWidget have a ValueNotifier, say savedGame that has the value you want to share.
Then in the route where you need to set the value
GameStateWidget.of(context).savedGame.value = ...
And in the route where you need the value
ValueListenableBuilder(
valueListenable: GameStateWidget.of(context).savedGame,
builder: (context, savedGameValue, child) => ...
)

show dialog when long pressed and pop it when finger up

I want to show a dialog when user long pressed on an item and pop it when finger up but it can't detect tap up.
I put dialog on another GestureDetector and use onTapUp property of it to pop dialog.
GestureDetector(
child: studentIcon(index, context),
onLongPress: () {
showDialog(
context: context,
builder: (context) {
return GestureDetector(
onTapUp: (detail) {
Navigator.pop(context);
},
child: DialogDetail(
index: index,
),
);
});
},
I expect to pop dialog after finger up after long pressed.
You can't do that as there is an context problem in GestureDetector.
Please follow this answer to implement this thing.
Try to make method to open dialog . i provide alert dialog code..
void _showText(BuildContext context) {
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return AlertDialog(
content: Text(
"User name :${nameEditText.text} \nPassword : ${passwordEditText.text}"),
actions: <Widget>[
new FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: new Text("OK"))
],
);
});
}
}
after that called on button click..
child: RaisedButton(
padding: EdgeInsets.all(15.0),
onPressed: () {
_showText(context);
},
child: Text(
"Submit",
style: TextStyle(fontSize: 15, color: Colors.white),
),
color: Colors.blue,
),