-
Use Case: I want the user to be able to go directly to: This is similar to the profile page of Twitter PWA where the
Screen.Recording.2021-11-23.at.12.37.07.AM.movIssue late final _router = GoRouter(
urlPathStrategy: UrlPathStrategy.path,
routes: [
GoRoute(
path: '/',
pageBuilder: (context, state) {
return MaterialPage(
key: state.pageKey,
child: const HomePage(),
);
},
routes: [
GoRoute(
path: 'profile/:section',
pageBuilder: (context, state) {
final section = profileSectionfromString(state.params['section']!);
return MaterialPage(key: state.pageKey, child: ProfilePage(initialSection: section));
},
)
],
)
],
); If the user try to go directly to
I tried to make the last three tabs (i.e. Discussion: Is there something that I'm missing and is this possible to achieve by other means? If this is not possible, should this turn into feature request? For instance, an the API could look something like this: GoRoute(
// the question mark indicates that the param and rest of the path after is optional and can be null/empty
path: 'profile/?:section',
pageBuilder: (context, state) { /* */},
) Fully Runnable Code Sample// ignore_for_file: constant_identifier_names
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: _router.routeInformationParser,
routerDelegate: _router.routerDelegate,
title: 'Nested Navigation Example',
);
}
late final _router = GoRouter(
urlPathStrategy: UrlPathStrategy.path,
routes: [
GoRoute(
path: '/',
pageBuilder: (context, state) {
return MaterialPage(
key: state.pageKey,
child: const HomePage(),
);
},
routes: [
GoRoute(
path: 'profile/:section',
pageBuilder: (context, state) {
final section = profileSectionfromString(state.params['section']!);
return MaterialPage(key: state.pageKey, child: ProfilePage(initialSection: section));
},
)
],
)
],
errorPageBuilder: (context, state) {
return MaterialPage(
key: state.pageKey,
child: ErrorPage(state.error),
);
},
);
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Home Page'),),
body: Center(
child: TextButton(
onPressed: () {
context.go('/profile/posts');
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(Icons.person),
Text(' Profile'),
],
),
),
),
);
}
}
class ProfilePage extends StatefulWidget {
final ProfileSections initialSection;
const ProfilePage({
Key? key,
required this.initialSection,
}) : super(key: key);
@override
_ProfilePageState createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> with SingleTickerProviderStateMixin {
late final TabController _controller;
@override
void initState() {
// TODO: implement initState
super.initState();
_controller = TabController(
length: ProfileSections.values.length,
vsync: this,
initialIndex: widget.initialSection.index,
);
}
void _tap(int index) {
context.go('/profile/${ProfileSections.values[index].asString().toLowerCase()}');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Profile Page'),
bottom: TabBar(
controller: _controller,
tabs: [for (final f in ProfileSections.values) Tab(text: f.asString())],
onTap: (index) => _tap(index),
),
),
body: TabBarView(
controller: _controller,
children: [
for (final f in ProfileSections.values)
Center(
child: Text(f.asString()),
)
],
),
);
}
}
enum ProfileSections {
Posts,
Likes,
Favourites,
Following,
}
ProfileSections profileSectionfromString(String string) {
return ProfileSections.values.firstWhere(
(element) => describeEnum(element).toLowerCase() == string.toLowerCase(),
orElse: () => ProfileSections.Posts,
);
}
// String profileSectionToString(ProfileSections section) => describeEnum(section);
extension on ProfileSections {
String asString() => describeEnum(this);
}
/// sample error page
class ErrorPage extends StatelessWidget {
const ErrorPage(this.error, {Key? key}) : super(key: key);
final Exception? error;
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text('Page Not Found')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(error?.toString() ?? 'page not found'),
TextButton(
onPressed: () => context.go('/'),
child: const Text('Home '),
),
],
),
),
);
} |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 10 replies
-
optional parameters can be passed using |
Beta Was this translation helpful? Give feedback.
-
You could do this: GoRoute(
path: 'username',
redirect: (_) => '/username/home',
routes: [
GoRoute(path: ':section', ...),
]
) |
Beta Was this translation helpful? Give feedback.
-
Well, that's just an embarrassing error for several reasons:
I believe all of that is fixed with v2.3.0. can you please verify? I'm using you as a guinea pig for the new docs. I've gotten a working version of your app running using what I think are good instructions, but I'd love you to help me test the end-to-end. Also, I noticed that your tabbed example doesn't use |
Beta Was this translation helpful? Give feedback.
-
Follow up: The main difference is that when the user is at the home tab, Screen.Recording.2021-11-24.at.4.46.36.PM.movBefore this discussion, I wasn't aware that two routes can be defined as shown below (i.e. routes: [
GoRoute(
path: 'profile',
pageBuilder: (context, state) {
return MaterialPage(
key: profileKey,
child: const ProfilePage(
initialSection: ProfileSections.Home,
),
);
},
),
GoRoute(
path: 'profile/:section',
pageBuilder: (context, state) {
final section = profileSectionfromString(state.params['section']!);
return MaterialPage(
key: profileKey,
child: ProfilePage(
initialSection: section,
),
);
},
),
], Fully runnable example for reference can be found here: |
Beta Was this translation helpful? Give feedback.
-
Yep. That works too. |
Beta Was this translation helpful? Give feedback.
-
@renanmgs pretty much any LocalKey-derived object would do the trick, e.g. final profileKey = ValueKey('profile-page'); |
Beta Was this translation helpful? Give feedback.
Well, that's just an embarrassing error for several reasons:
SelectableText
so that even if I had provided a good error message with a link, you would've have been able to copy-paste it anywayI believe all of that is fixed with v2.3.0. can you please verify? I'm using you as a guinea pig for the new docs. I've gotten a working version of your app running using what I think are good instructions, but I'd love you to help me test the end-…