A lightweight Flutter package that bridges GoRouter with GetX controllers — allowing you to seamlessly manage route-based controller initialization without relying on GetX's routing system.
- Automatic controller binding on route entry.
- Controller lifecycle handled automatically via
StatefulWidget. - Supports
lazyandpermanentcontroller instantiation. - GoRouter-compatible route redirection and validation.
- Fully customizable transitions via
CustomTransitionPage. - Supports multiple controllers and tagging (
tag) per route.
flutter pub add getx_goControllerRoute(
path: '/profile',
routeControllerConfig: ProfileRouter(),
)Each route must extend RouteControllerConfig and provide a builder that returns ControllerBindingEntry:
class ProfileRouter extends RouteControllerConfig {
@override
GetxGoBuilder builder() {
return (context, state) {
return ControllerBindingEntry(
controllers: [
ControllerEntry<ProfileController>(() => ProfileController()),
],
view: () => const ProfileView(),
);
};
}
}Used to define how a controller is created and managed.
ControllerEntry<ProfileController>(
() => ProfileController(),
tag: 'optional-tag',
lazy: true,
permanent: false,
)Wraps your view and handles all controller registration/disposal:
ControllerBindingEntry(
controllers: [
ControllerEntry(...),
ControllerEntry(...),
],
view: () => YourWidget(),
)ControllerEntry<ChatController>(
() => ChatController(),
tag: state.extra as String,
)And inside the view:
class ChatView extends GetView<ChatController> {
final String chatId;
@override
String get tag => chatId;
}You can use redirect() to validate route conditions and cancel navigation:
@override
Redirect redirect() {
return (context, state) {
final token = state.uri.queryParameters['token'];
if (token == null) {
preventNavigation(state: state, message: 'Missing token');
}
return null;
};
}If transitionsBuilder() is provided, the route will use CustomTransitionPage:
@override
CustomTransitionBuilder? transitionsBuilder() {
return (context, animation, secondaryAnimation, child) {
return FadeTransition(
opacity: animation,
child: child,
);
};
}GoRouter(
routes: [
ControllerRoute(path: '/login', routeControllerConfig: LoginRouter()),
ControllerRoute(path: '/chat', routeControllerConfig: ChatRouter()),
ControllerRoute(path: '/profile', routeControllerConfig: ProfileRouter()),
],
);class ChatRouter extends RouteControllerConfig {
@override
GetxGoBuilder builder() {
return (context, state) {
final chatId = state.extra as String;
return ControllerBindingEntry(
controllers: [
ControllerEntry<ChatController>(() => ChatController(), tag: chatId),
],
view: () => ChatView(chatId: chatId),
);
};
}
@override
Redirect? redirect() {
return (context, state) {
final chatId = state.extra as String?;
if (chatId == null || chatId.isEmpty) {
preventNavigation(state: state, message: 'Chat ID is required');
}
return null;
};
}
}- Use
permanent: trueif you want your controller to persist across route changes. - Use
lazy: falseif you want the controller to be instantiated immediately. - Be careful with
taggedcontrollers; make sure your view overridestagproperly.
Pull requests and issues are welcome!
If you find this package useful, consider starring the repo 🌟