Flutter webpage navigation - flutter

How to get following result in flutter web app using Getx package
On tapping the container in intiating screen, I wish to pass parameters in following fashion ( 2 variable parameters and 1 fixed parameter i.e. product) which should open webpage with following url
https://myapp.local/variableParameter1/variableParameter2/product
Above link should be without # and also when user opens above link, should lead to (ProductScreen) with 2 parameters being passed as arguments
My code is structured in following fashion and works well on mobile devices.
Part of intiating screen
GestureDetector(
child: Container(
//some content inside
),
onTap: () {
Get.toNamed(
'/product/$variableParameter1/$variableParameter2',
);
},
)
Part of main.dart file
GetPage(
name: '/productscreen/variableparameter1/variableparameter1',
page: () => ProductScreen(),
binding: ProductScreenBinding(),
),
Part of controllers for ProductScreen
class ProductController extends GetxController {
var screenprm1 =Get.arguments[0].toString().obs;
var screenprm2 =Get.arguments[1].toString().obs;
}

Related

Flutter : How to close alertdialog from another file

I have 2 dart file. I want close the alertdialog from another dart file in specific conditions.
How can I ?
for example the function i want.(I wrote to express myself better.)
void example(){
if(control==false){
alertDialog.close();
}
Alert dialog file
class AlertForm extends StatefulWidget {
#override
_AlertFormState createState() => _AlertFormState();
}
class _AlertFormState extends State<AlertForm> {
void _showDialog() {
// flutter defined function
showDialog(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
title: new Text("Alert Dialog title"),
content: new Text("Alert Dialog body"),
actions: <Widget>[
// usually buttons at the bottom of the dialog
new FlatButton(
child: new Text("Close"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
So what I want is to use the pop action in a function in another flutter file.
Call Navigator.of(context).pop(); inside the if block (of the void example function of the other Dart file) and the alert should close.
But here is the problem, the context above might not be part of or aware of the dialog and the above may not work.
More info about your setup would suggest a solution to this problem. Like how exactly does the other Dart file exist relative to the file where _showDialog is declared? If it's something you can easily provide context from AlertForm Dart file to the closingDialog Dart file, then you should know what to do. If that's not the case then a navigator key should help.
You can keep a navigator key for the entire application. Then instead of closing the dialog with Navigator.of(context).pop();, you use navigatorKey.currentState!.pop();.
You should have properly setup the navigator key yourself. Refer to this Stackoverflow answer for how to do that: https://stackoverflow.com/a/72945522/13644299
It is not compulsory to use get_it package. You can simply export the NavigationService (that will keep the navigatorKey) from any Dart file or with any method you deem fit, depending on your current state management architecture.

Passing model object as an argument with Flutter GetX

I need a model object on two screens.
I have 2 questions:
Is passing a model object (from one screen to another) required if we are using GetX?
If yes, how do we do it?
return GestureDetector(
onTap: () {
Get.toNamed('/field_details/', arguments: fieldModel);
},
In main.dart:
GetPage(
name: '/field_details',
page: () => FieldDetailsScreen(//how do I get the model to be passed here, it won't be available in the main function),
),
You can use Get.arguments for that.
GetPage(
name: '/field_details',
page: () => FieldDetailsScreen(Get.arguments),
),
You will get your model here but you need to convert arguments into model by using your model's fromjosn method.

Flutter getx: separate each binding inside own binding when I don't use navigator

I am using getx. I have a main Page inside my application and mainBinding. Inside main page I have a Tabbar. Main Page has many pages that any pages loaded in this way:
child: TabBarView(
controller: controller.tabController,
physics: const NeverScrollableScrollPhysics(),
children: [
ReportOverallPage(),
Container(),
Container(),
Container(),
Container(),
Container(),....
],
),
As you can see ReportOverallPage() page not used of Navigator means not pushed into stack bay navigator so I cant create a binding for each pages.
each pages have own repository and controller. Now I have to add all controllers and repositories inside MainBinding.
class MainViewBinding implements Bindings {
#override
void dependencies() {
Get.lazyPut<MainViewController>(() => MainViewController());
Get.lazyPut<ReportController>(
() => ReportController(Get.find<ReportRepository>()));
Get.lazyPut<ReportRepository>(
() => ReportRepositoryImp(Get.find<RestClient>()));
.........
}
}
Now MainBainding has a long list of Putted class.How can I separate each binding class inside own binding class when I don't use navigator?
I'm afraid there's no straightforward way to do that. Because bindings are page specific (or navigation) you have to bind the dependencies with the page. Tabs aren't pages. Therefore you don't directly bind dependencies to them. You need to bind them with the containing page.
But one workaround could be you create separate binding class and then call the dependencies() method of each of them inside the dependencies() method of your MainBinding class.

pop and push the same route back with different params in Futter (GET X)

I have 2 screens,
Screen one contains a list view with onPressed action on every item
screen two contains the detail of the pressed item as well as a drawer with the same list view as screen one.
What I want to do here is when the user goes to the detail screen and click on an item from the drawer the detail screen should pop and push back with new params.
Code so far,
Route
GetPage(
name: '/market-detail',
page: () => MarketDetail(),
binding: MarketDetailBinding(),
),
Binding
class MarketDetailBinding extends Bindings {
#override
void dependencies() {
Get.lazyPut(() => MarketDetailController());
}
}
Click action in screen one
onTap: () {
Get.toNamed('market-detail',
arguments: {'market': market});
},
Detail Screen Class
class MarketDetail extends GetView<MarketDetailController> {
final Market market = Get.arguments['market'];
}
Click action in detail screen sidebar
onTap: () {
Get.back();
Get.back();
Get.toNamed('market-detail',
arguments: {'market': market});
},
First Get.back() is to close the drawer, then remove the route and push the same route back again,
Expected behaviour,
MarketDetailController should be deleted from memory and placed again,
What actually happening
The controller only got delete and not getting back in memoery on drawer click action until I hot restart the app(By clicking save).
If anybody understands it, please help I am stuck here.
As I can see, you're trying to pop and push the same route with a different parameter in order to update a certain element on that route. Well, if that's the case then just let me show you a much better way.
In your MarketDetailController class you should add those:
class MarketDetailsController extends GetxController {
// A reactive variable that stores the
// instance of the market you're currently
// showing the details of.....
Rx<Market> currentMarket;
// this method will be called once a new instance
// of this controller gets created
// we will use it to initialize the controller
// with the required values
#override
void onInit() {
// some code here....
// .......
// intializing the variable with the default value
currentMarket = Market().obs;
super.onInit();
}
void updateCurrentMarket(Market market) {
// some code here if you need....
// updating the reative variable value
// this will get detected then by the Obx widgets
// and they will rebuild whatever depends on this variable
currentMarket.value = market;
}
}
Now inside your page UI, you can wrap the widget that will display the market details with the Obx widget like this:
Obx(
() {
final Market currentMarket = controller.currentMarket.value;
// now you have the market details you need
// use it and return your widget
return MyAwesomeMarketDetailsWidget();
},
)
Now for your click action, it can just be like this:
onTap: () => controller.updateCurrentMarket(myNewMarketValue)
This should be it. Also, I advise you to change GetView to GetWidget and Get.lazyPut() to Get.put()

How to route file to a different page in flutter

I'm making an app with Dart/ flutter now and having an issue with routing pages.
The app is basically the matching app, and I want to add the functionality that a user can edit their profile. Currently, we have 4 stateful widgets: Match(), Message(), MyProfile() and EditProfile(). In the bottom navigation bar, I put three widgets, Match(), Message(), and MyProfile(); when the user wants to change the profile information, the person goes to MyProfile() and click "edit profile" button, which takes the user to EditProfile. After the user changes the information, I want to rout the page to MyProfile() for allow the user to check the profile info.
The code below is some part of the Navigation bar.
class _NavigationHomeState extends State<NavigationHome> {
int _currentIndex = 0;
final List<Widget> _children = [
Match(),
Messages(),
MyProfile(),
];
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
and I put the code below in one of the button of the EditProfile().
Navigator.of(context).pushNamed('/myProfile');
Then gave me an error saying
Error: Could not find the correct Provider above this
MyProfile Widget
This likely happens because you used a BuildContext that does not
include the provider of your choice. There are a few common scenarios:
The provider you are trying to read is in a different route.
Providers are "scoped". So if you insert of provider inside a route,
then other routes will not be able to access that provider.
You used a BuildContext that is an ancestor of the provider you are trying to read.
Make sure that MyProfile is under your
MultiProvider/Provider. This usually happen when you are
creating a provider and trying to read it immediatly.
I guess I'm getting this error because we set the _currentIndex in the bottom navigation bar as 0, which is Match(), so Navigator.of(context).pushNamed('/myProfile'); trying to take the user to the Match() page (?)
How can we take the user to the MyProfile page after the person save and click the button on EditProfile()?
Try using MaterialPageRoute instead of named routes.
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
}
If you going to EditProfile from MyProfile widget then I suggest to just pop the screen. As this will not reload complete screen, you can always pass data while doing pop.
RaisedButton(
onPressed: () {
// The Yep button returns "Yep!" as the result.
Navigator.pop(context, 'Yep!');
},
child: Text('Yep!'),
);
Another option is to use pushNamedAndRemoveUntil method.
navigator.pushNamedAndRemoveUntil('/MyProfile', ModalRoute.withName('/MyProfile'));
I guess I'm getting this error because we set the _currentIndex in the
bottom navigation bar as 0, which is Match(), so
Navigator.of(context).pushNamed('/myProfile'); trying to take the user
to the Match() page (?)
Not sure about your error but you can pass data as argument while doing pushNamed.
RaisedButton(
child: Text("Navigate to MyProfile"),
onPressed: () {
Navigator.pushNamed(
context,
'/myProfile',
arguments: [
'Extract Arguments Screen',
'This message is extracted in the build method.',
],
);
},
),