Passing multiple rows of data in flutter - flutter

How can I pass multiple rows of data from one screen to the second one without overloading the values of the first data passed?
onPressed: () {
setState(() {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => new orderpage(
'${widget.productName.toString()}',
'$total',
counter,
check_tandeef,
check_makwa,
sab8a)));

I think I understood your point, I'm not sure.
To pass values, you can use args in the Navigator and the use those values in your second screen.
https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments
Another way, would be using InheritedWidget class, so you can use the same instance of an object all across your widgets without being passing them by the context
https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html

I am assuming you mean you wan't to pass multiple sets of the same data to the next screen. You could do this by creating a class which holds all your params, and then pass a list to your Screen.
class myViewModel{
String param1;
String param2;
int param3;
bool param4;
myViewModel(this.param1,this.param2,this.param3,this.param4);
}
Create the list and fill it with instances of the Class:
listOfParams = List<myViewModel>();
Pass the List:
onPressed: () {
setState(() {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => new orderpage(
listOfParams
)));

Related

How to delete data when navigator from screen to another in Flutter?

every one!
My problem is when I store the data in the list coming from the api and I display it on one page and then go back to another page and when I go back to the old page, the data is still there. Why ???
How do I delete the data??
In the code block that contains navigating logic, you can assign empty data to the data stored variable.
onTap: () {
variableContainingData = ''; // assign empty data here
Navigator.push(
context,
MaterialPageRoute(builder: (context) => NextPage()),
);
}
If you want to clear list initially then you need to implement that functionality in onInit() method.
Bellow code would be helpful for you.
List yourList = [];
#override
void initState() {
yourList.clear();
super.initState();
}
and at the time of navigation you can also clear your list based on your requirement:
onPressed: () {
yourList.clear();
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
}
But if you want to add some product at the time of page initialization then you need to add that specific logic(based on requirement) also in initState() method.

How do we pass or propagate data backwards through the Navigation stack in Flutter?

1.FlatButton(
onPressed: () async {
var typedName=await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return CityScreen();
},
),
);
print(typedName); //prints the value of cityName
}
2. FlatButton(
onPressed: () {
Navigator.pop(context, cityName);
},
The no.1 is coming from file loading_screen and no.2 is coming from city_screen. Can you anyone help me understand what is happening that when you pass a variable or anything in the pop? And when come that onPress method is still working because the the method Navigator.push has been already assigned to the variable but still that method Navigator.push is working when I pressed the button?Does that onPress doesn't care about the variable TypedName and just looks for the method Navigator.push?
If you use push method it will create the new screen over your current page and pop will remove last screen, you cannot pass name with both, you can check basics of navigation here, if you want to pass name to next page you should use something like pushnamed method and you can see the logic of passing name here. And for all methods you should check here.

How to navigate to a new screen after data is fetched from API in Flutter?

In my main.dart file I have a Future that fetches data from an API (json file).
What is the proper way that I can navigate to a new screen as soon as Future finishes fetching data?
You can do it like this:
yourFutureObject.then((){
//write the code you want to run as soon as your Future finishes
Navigator.push(context, MaterialPageRoute(builder: (BuildContext context) =>
YourNewPage()));
});
I used some general names because you didn't post any code but you can write the function you want to run when Future finished and pass it to Future’s then method
So you have a Method that returns a Future
bool asyncResult2 = await asyncFunc2();
if(asyncResult2)
{
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
}
asyncFunc2 funtion when completes the data fetching and assigning (or anything else) then all of these is done you can just pass the Future of boolean value true which states that every thing was done sucessfully and you can proceed to the second page or else if the the boolean value is false then there was something wrong with fetching or assigning

How to return data when popping multiple screens?

I know I can return data to the previous screen by using
Navigator.pop(context, 'Value');
But in my case I need to pop multiple screens by using
Navigator.popUntil(context, ModalRoute.withName('/login'));
I wonder in this case how do I pass the data back to the corresponding widget?
Thanks in advance.
you can send DATA in few ways
as a Parameter
using Shared_Preferences
using Static Variables
Only for Current Session
if you just need the DATA for Current Session you can go for Static Variables
step 1 : Create a Class and have Static Variable in it.
class Globaldata{
static String value;
}
step 2 : Initialise variable by
Globaldata.value="some_value";
step 3 : use of variable
String assigned_value = Globaldata.value;
The flutter API does not have that feature and from this https://github.com/flutter/flutter/issues/30112 discussion, that feature is not on the table yet. A walkaround was suggested though using the Page API.
However, in my opinion, it is cleaner to use the provider package https://pub.dev/packages/provider as part of your app state management to keep the data you want and make it available to any screen of interest. Follow these steps to achieve that.
Add the provider to your pubspec.yaml. Check the link above to see detailed instructions.
Create a notifier class that extends ChangeNotifier class as shown below. ChangeNotifier class is part of the flutter API.
class MyDataProvider extends ChangeNotifier {
//define your private data field(s). I'm using int here.
int _mydata;
//define a getter
int get myData => _myData;
// define a setter
set myData(newData){
_myData = newData;
notifyListeners();
}
}
Wrap your uppermost widget (or the parent of the screens where you want to pass the data) with the provider and instantiate it. I'm using main here.
void main(){
runApp(
ChangeNotifierProvider(create: (context) => MyDataProvider()),
child: MyApp(),
)
}
Assuming you have five screens: Screen1, Screen2, ..., Screen5 and you want to navigate to screen5, do some operations and return to screen1 with some data. On 1st screen, define a local variable for myData and create an instance of your myDataProvider. When a button is pressed to start the navigation, wrap up the push navigation in an asynchronous call.
//Screen1
int currentLocalData = 78;
MyDataProvider myProvider = Provider.of<MyDataProvider>(context);
onPressed: () async {
//Assign localData to myData in the provider
myProvider.myData = currentLocalData; //calls the setter define in the provider.
await Navigator.push(context, MaterialPageRoute(
builder: (context) => Screen5()
));
//Retrieve myData from the provider and assign it to currentLocalData.
//This executes after navigating back from Screen5
currentLocalData = myProvider.myData;
}
Let assume in Screen5 you retrieved the data and added 100 to it. Your aim is to return to Screen1 and make use of the new data, i.e 178. Here you will instantiate the provider again in Screen5 and assign the value 178 to myData.
//Screen5
MyDataProvider myProvider = Provider.of<MyDataProvider>(context);
myProvider.myData += 100;
//Use navigation.popUntil
Navigation.popUntil(context, ModalRoute.withName('/Screen1'));
Say you have Screen A,Screen B, Screen C. If you want to pop till Screen A and pass some data. Here is what you have to do.
1. Navigate from Screen A to Screen B
Navigator.pushNamed(context, '/screenb')
.then((value) {
//you will get return value here
});
2. To pop till Screen A.
//add thi code in Screen C
var nav = Navigator.of(context);
nav.pop('refresh');
nav.pop('refresh');

How named routes in Flutter eliminate duplication?

I cannot understand the reason why someone should use named routes, with Navigator.pushNamed(), instead of the normal way with Navigator.push().
The tutorial page states that:
if we need to navigate to the same screen in many parts of our apps,
this can result in code duplication. In these cases, it can be handy
to define a “named route,” and use the named route for Navigation
Duplication
How will the duplication be generated when using simple routing and how it will can be eliminated with the use of named routes?
I fail to understand what is the difference of
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
from
Navigator.pushNamed(context, '/second');
in the context of duplication.
Consider you go with Navigator.push() in many widgets:
// inside widget A:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
// inside widget B:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
// inside widget C:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
Now let say you need to change your App and the widget SecondRoute needs to receive a value on it's constructor. Now you have a problem, since you have multiple copies of the same code on several locations, you need to make sure you will update all of those copies, which can be tedious and error prone:
// inside widget A:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute(
title: 'Title A',
)),
);
// inside widget B:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute(
title: 'Title B',
)),
)),
);
// inside widget C:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute(
title: 'Title A', // ERROR! Forgot to change the variable after a copy/paste
)),
)),
);
Now let's consider you go with named routes.
Firstly I would never recommend anyone to actually use the name directly for navigation, but instead use a static variable reference, this way if you need to change it in the future its way simpler and secure, as you can't forget to update it anywhere, like this:
class Routes {
static const String second = '/second';
}
Another way is to have a reference inside the route itself, a static const String inside SecondRoute, so we can use it as SecondRoute.routeName. It's a matter of personal preference IMO.
Then your widgets will navigate using:
// inside widget A:
Navigator.pushNamed(context, Routes.second); // Routes.second is the same as '/second'
// inside widget B:
Navigator.pushNamed(context, Routes.second);
// inside widget C:
Navigator.pushNamed(context, Routes.second);
Now if you need to pass a parameter to SecondRoute upon creation you can do it in a centralized location using the MaterialApp onGenerateRoute, as this tutorial explains in more detail. Your code will be changed to:
// inside widget A:
Navigator.pushNamed(context, Routes.second, arguments: 'Title A');
// inside widget B:
Navigator.pushNamed(context, Routes.second, arguments: 'Title B');
// inside widget C:
// You can still make mistakes here, but the chances are smaller.
Navigator.pushNamed(context, Routes.second, arguments: 'Title C');
MaterialApp(
onGenerateRoute: (settings) {
if (settings.name == Routes.second) {
final String title = settings.arguments;
return MaterialPageRoute(
builder: (context) => SecondRoute(title: title),
);
}
},
);
The amount of duplicated code is decreased, but on the other hand the onGenerateRoute code gets more complex as you make more routes, as all of their creation will be centralized there, so IMHO it's more about a personal preference then a general guideline.
Push and PushNamed have the similar effect, Push will switch to the route you specified while PushNamed will switch to the route with the route name specified.
What the Tutorial page means for duplication is duplication of code not duplication of routes.
For instance, you have a route where you would want to check whether the user is signed in and show the corresponding page
Using Push only:
Page1:
//This is page 1....
RaisedButton(
child: Text('Go to second'),
onPressed: () {
if (user.state = "login") {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPage(),
),
)
}else{
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPageAnonymous(),
),
)
}
}
)
....
In another page, Page2, you will need to repeat the same code:
//This is page 2....
RaisedButton(
child: Text('Go to second'),
onPressed: () {
if (user.state = "login") {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPage(),
),
)
}else{
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPageAnonymous(),
),
)
}
}
)
....
With PushNamed, you just have to declare it once and you can basically reuse it over and over again.
In your onGenerateRoute:
onGenerateRoute: (settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(builder: (_) => FirstPage());
case '/second':
if (user.state = "login") {
return MaterialPageRoute(
builder: (_) => SecondPage()
);
}else{
return MaterialPageRoute(
builder: (_) => SecondPageAnonymous()
);
}
default:
return _errorRoute();
}
},
Now in ANY pages in your project, you could do this:
Navigator.of(context).pushNamed('/second')
Without needing to repeat the checking of sign in or even the error handling every time you used it. The obvious benefit is that you can stay consistent throughout the app by preventing duplicate code piece, instead of repeating it again and again.
Now, this however DOES NOT prevent duplicates of routes! There is no different between push and pushNamed in this context!
But since your routes are now named, you can do popUntil('/') easily to go back to the first instance of the route, instead of creating it again or PushReplacementNamed.
The only advantage I can see using Navigate with named routes is to have routes declared inside your MaterialApp, so that developer can only be used assigned routes i.e widgets, pages,
If anyone uses other than that, It will give an error 'onUnknownRoute is called.'
Here is my beginner flutter thoughts:
It makes the code cleaner: Without declaring the routes at the level higher widgets, new screens will appear out of nowhere, in response to anything that happens in the app. It is much easier to understand the navigation skeleton/ structure when you declare the routes together, and even more so at a higher widget, especially for other developers. Of course, this doesn't help with understanding exactly when those routes are actually navigated to, but its a small improvement, and brings us back into the declarative paradigm. The hint provided by the declared routes will help a newer developer understand your navigation flow.
For folks visiting this question in 2022. Flutter actually now recommends not using named routes
Note: Named routes are no longer recommended for most applications. For more information, see Limitations in the navigation overview page.
https://docs.flutter.dev/cookbook/navigation/named-routes
If you use push(), you have to import the file in which SecondRoute is located every time you need to navigate to that screen. This is excessive code duplication for big projects that you need to navigate around the different screens.
If you use pushNamed(), you need to define the routes only once in your MaterialApp. Then, you can navigate to any screen from anywhere without repeating the same thing like you have to with push().
Another big reason to choose PushNamed() over the other one is to be able to build your own navigation system with it. You can decide whether or not routes are available for certain users even before they navigate to the screen.
for understanding why we should use Navigator.pushNamed instead Navigator.push first let's be familiar with Navigator methods. did you ever heart about Navigator.popUntil or Navigator.pushAndRemoveUntil?
we use Navigator.popUntil when we want to pop in the stack to a specific route. if you check the documentation you can find that it's very easy to use these methods with the pushNamed method. also, check all methods in the documentation. when I try to understand routing in flutter this article was very useful for me.
and as a disadvantage, it's very hard to handle parameters in this approach. you should create onGenerateRoute and handle parameters for each route.