Flutter : clear child Texfield when Navigator pop - flutter

I am making the sign up of my app in Flutter and this process is on 2 pages. On the first page, I use my own class for Textfields, passing arguments to them.
When I pop from the second page to the first, I would like to reset all data from the first page. I succeed to do that but I have a problem : the text in the textfields is not cleared despite the fact that the variables that receive the content of the Textfields are reset.
It gives for the first page :
class Inscription1 extends StatefulWidget {
Inscription1({Key? key}) : super(key: key);
#override
State<Inscription1> createState() => _Inscription1State();
}
class _Inscription1State extends State<Inscription1> {
String nom = "";
and
TextFieldInscription(hint: "Nom", updateValeur: (nouvelleValeur){setState(() {nom = nouvelleValeur;});},),
To pass the data to the second page and force rebuild the first page when the second page pops, I have the following in the first page
Navigator.of(context).push(MaterialPageRoute(builder: (context) => Inscription2(nom: nom,)).then(remettreAZero);
where remettreAZero is the following function
FutureOr remettreAZero(value){
setState(() {
nom = "";
});
rebuildAllChildren(context);
}
and rebuildAllChildren
void rebuildAllChildren(BuildContext context) {
void rebuild(Element el) {
el.markNeedsBuild();
el.visitChildren(rebuild);
}
(context as Element).visitChildren(rebuild);
print("rebuild");
}
All this works ("nom" is set empty) but the page still shows the TextField with the value previously entered inside.
I even tried to pass a controller argument in the TextField and adding
controller?.clear();
inside the function remettreAZero but it doesn't help.
Could you help me?
Many thanks !
Bernard

You have to dispose your textfield controller like this on first screen
#override
void dispose() {
textEditingController.dispose();
}

Related

How to change the default routing behavior when entering a new URL through address bar in a flutter web app? (using getx)

I am working on a Flutter Web App using Getx for navigation and state management. One of the routes in my flutter app has two query parameters. Let us call these parameters Dataset and Index. When the Dataset parameter is changed through the URL, I want to make an API call to retrieve the new dataset, and when the Index parameter is changed, I want to display the data from the dataset at that particular index on the app. Index in this case is an observable RxInt variable defined in the controller.
However, the default behavior when I change the URL and press enter is for the Flutter app to push a new page on to the navigation stack. The behavior I prefer is to simply update the values and make a new API call if necessary. The API call may be done by simply refreshing the page since it is handled by the Getx controller onInit function.
I'm not very familiar with how routing in flutter works and I haven't found a solution to change the behavior for routing itself. I've tried a few ways to update the values despite pushing the new page on to the stack, such as setting the value for index through the initState or build calls on my widgets but those changes aren't visible on my UI. I've also tried reinitializing the controller by deleting it but that didn't work either.
EDIT: I have added a code example:
Widget:
class MainscreenView extends StatefulWidget {
const MainscreenView({Key? key}) : super(key: key);
#override
State<MainscreenView> createState() => _MainscreenViewState();
}
class _MainscreenViewState extends State<MainscreenView> {
late MainscreenController mainscreenController;
#override
Widget build(BuildContext context) {
return GetX<MainscreenController>(
init: MainscreenController(),
initState: (_) {
mainscreenController = Get.find<MainscreenController>();
},
builder: (_) {
return Scaffold(
body: Center(
child: Text(
'Current index is ${mainscreenController.index.value}',
style: const TextStyle(fontSize: 20),
),
),
);
});
}
}
Controller:
class MainscreenController extends GetxController {
final index = 0.obs;
late String? dataset;
#override
void onInit() {
super.onInit();
final String? datasetQuery = Get.parameters['dataset'];
if (datasetQuery != null) {
dataset = datasetQuery; //API call goes here
} else {
throw Exception('Dataset is null');
}
final String? indexString = Get.parameters['index'];
if (indexString == null) {
throw Exception('Index is null');
} else {
final int? indexParsed = int.tryParse(indexString);
if (indexParsed == null) {
throw Exception('Index Cannot be parsed');
} else {
index.value = indexParsed;
}
}
}
}
The initial route is /mainscreen?dataset=datasetA&index=0. If I were to modify the route in the address bar to /mainscreen?dataset=datasetA&index=5 for example and press enter, The current behavior of Flutter is to push a new page onto the navigation stack. I would like to update the value of index instead and display it on the same page, but I haven't found a way to accomplish this. Also, if dataset parameter is updated I would like to again avoid pushing a new page onto the stack and refresh the current page instead so that the onInit function is run again and the API call is made automatically.

How to use GetX for data passing in Flutter?

My first Flutter development with GetX. Now encounter a problem.
I have a ListView where the items are all encapsulated Class.
The requirement now is to create an obs List as a data source. The elements in the List are all models.
I now want to pass the model in the List to the item, and click on the item to pass it to the next page for data modification. what should I do?
I am like this
`
Controller:
class FindQADetailController extends GetxController {
var detailEntity = QADetailEntity().obs;
}
Page:
class FindQAPage extends StatefulWidget {
const FindQAPage({Key key}) : super(key: key);
#override
State<FindQAPage> createState() => _FindQAPageState();
}
class _FindQAPageState extends BasePageMixin<FindQAPage, FindQAPresenter>
with SingleTickerProviderStateMixin
implements FindQAIView {
final findQAController = Get.put(FindQAController());
#override
void initState() {
super.initState();
_refresh();
}
#override
Widget build(BuildContext context) {
return RezaAppContainer(
childWidget: Obx(() => DeerListView(
itemCount: findQAController.listData.length,
onRefresh: _refresh,
loadMore: _loadMore,
hasMore: findQAController.hasMore,
itemBuilder: (_, index) {
var entity = findQAController.listData[index];
return FindItemQAPage(entity);
})),
);
}
Item:
class FindItemQAPage extends StatefulWidget {
FindItemQAPage(this.entity, {Key key}) : super(key: key);
QAEntity entity;
#override
State<FindItemQAPage> createState() => _FindItemQAPageState();
}
class _FindItemQAPageState
extends BasePageMixin<FindItemQAPage, FindItemQAPresenter>
with SingleTickerProviderStateMixin
implements FindItemQAIView {
FindItemQAController findItemQAController = Get.put(FindItemQAController());
#override
void initState() {
super.initState();
findItemQAController.entity.value = widget.entity;
}
}
`
I want the elements in the array in the first page to be passed to the item and the next page, and the data modifications made on the next page to be passed to the item in the first page.
Passing Data from 1st Screen to 2nd Screen
You can pass any data using arguments parameters in navigation methods
Get.to(ScreenName(),arguments: PASS_DATA);
If you are doing navigation with routes still you can pass data
Get.toNamed(RoutesName, arguments: PASS_DATA);
For navigate data back from 2nd screen to 1st screen you can user result property.
Get.back(result:PASS_DATA);
Pass data from 1st screen to 2nd screen & vice versa.
1st screen controller
import 'package:get/get.dart';
class FirstController extends GetxController {
/// Navigation method.
Future<void> btnNavigateTap() async {
//.... Using Get.toNamed method || use this if you are using routeName
//.... Pass Data from 1st screen to 2nd screen
Get.toNamed(
SeconScreenRouteName,
arguments: {
"user": "Jems",
"emails": ["abc#gmail.com", "pqr#gmail.com"],
},
);
//.... Using Get.to method
//.... Pass Data from 1st screen to 2nd screen
Get.to(
SecondScreen(),
arguments = {
"user": "Jems",
"emails": ["abc#gmail.com", "pqr#gmail.com"],
},
);
//.... Get Data from 2nd screen to 1st screen
final result = await Get.to(
SecondScreen(),
arguments = {
"user": "Jems",
"emails": ["abc#gmail.com", "pqr#gmail.com"],
},
);
}
}
2nd screen controller to access data.
import 'package:get/get.dart';
class SecondController extends GetxController {
late String user;
late List<String> emails;
dynamic argumentData;
#override
void onInit() {
super.onInit();
user = argumentData['user'];
emails = argumentData['emails'];
}
void btnBackTap(){
//... Passing data to previous screen.
Get.back(result:{
"user":"Jack",
});
}
}
For more details about navigation & parsing data using getX check this reference link

How to display popup after navigating back to previous screen in flutter?

I have a scenario where i have one popup in screen A .It will be triggerd from initstate() . User can navigate to screen B after clicking on button inside the popup . How can i show the popup if user come back to screen 1 by clicking on arrow back button ?
You can achieve with the help of .then() : https://api.flutter.dev/flutter/dart-async/Future/then.html
Navigator.of(context)
.push(CupertinoPageRoute<Screen1>(
builder: (context) => Screen2(
))).then((value) {
//ShowPopUpMenu() <-- Your PopUpMenu.
});
Add a boolean parameter to your screen if you want the popup:
class PopScreen extends StatefulWidget {
PopScreen (this.displayPopup);
final bool displayPopup;
#override
_PopScreenState createState() => _PopScreenState();
}
class _PopScreenState extends State<PopScreen> {
#override
void initState() {
super.initState();
if(widget.displayPopup){
// display your popup here
}
}
}
call to the navigator:
Navigator.pushNamed(context, '/yourscreen', arguments: true);

Change loaded Widget outside of Main file (setState not available)

I have a MainScreen() file where I defined two Widgets, side by side:
Left menu (ListTiles).
Main View (rest of screen, to the right).
My issue is that I need to tap the ListTiles on the left and dynamically change the Widget loaded on the Main View.
Any suggestions?
The main view must be stateful for this to work, as you need to trigger a rerender once you tap one of the tiles. You want to pass a callback function from your main screen to your menu of list tiles.
Your best bet is to setup an enum and have each listtile provide the callback with its own enum value.
Once you have the callback in your list of tiles, you can easily pass it onward to the individual tiles. Then, execute the callback function onTap and provide it with the correct enum value.
On your main screen, you just show the correct widget by looking at the current enum value.
class MainScreen extends StatefulWidget {
const MainScreen({Key? key}) : super(key: key);
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
MyEnum _currentTile = MyEnum.Home;
void _callbackFunction(MyEnum tileOption) {
setState(() {
_currentTile = tileOption;
});
}
#override
Widget build(BuildContext context) {
return MyCustomListTile((MyEnum tile) => _callbackFunction(tile) );
}
}

Flutter: A variable passed to the next screen becomes null

I want to pass a variable to the next screen but it becomes null in the next screen. what am I wrong with this? My code is like below.
first_screen.dart
onTap: () {
print(doc); // Prints out Instance of `DocumentSnapshot` on log
Navigator.of(context).pushNamed('/second', arguments: doc);
},
second_screen.dart
class SecondScreen extends StatefulWidget {
final DocumentSnapshot doc;
SecondScreen({
this.doc,
});
#override
State<StatefulWidget> createState() {
return _SecondScreenStateState();
}
}
class _SecondScreenState extends State<SecondScreen> {
#override
void initState() {
super.initState();
print(widget.doc); // Prints out null here
}
I tried with othe data types but all variables become null in the next screen.
You have to pass argument like this:
Navigator.of(context).pushNamed('/second', arguments: doc);
for you is true but, use the ModalRoute.of() method to returns the current route with the arguments like this:
final doc = ModalRoute.of(context).settings.arguments as String;
I assumed that doc is String.
If you're sharing data between widgets (screens) try looking at InheritedWidget.Take a look at https://www.youtube.com/watch?v=1t-8rBCGBYw. You can also look at state management packages like provider which is pretty easy to understand or a bloc. These will save you in the long run.