Milad-Akarie / auto_route_library

Flutter route generator
MIT License
1.58k stars 402 forks source link

Route name / not found #284

Closed McCrafterIV closed 3 years ago

McCrafterIV commented 3 years ago

Hey :)

I completely rewrote the routing definition, since then, when I open the app, only the message Route name / is not found! is shown on a blank red page. The weird thing is, that I've defined a route with the path / which I would guess is meant by the error message. Here is my route definition:

@MaterialAutoRouter(
  routes: <AutoRoute>[
    MaterialRoute(
      page: SplashPage,
      name: 'splash',
      path: '/'
    ),
    MaterialRoute(
      page: SignInPage,
      name: 'signIn',
      path: '/sign-in',
    ),
    MaterialRoute(
      page: MainApp,
      path: '/app',
      name: 'app',
      children: <MaterialRoute>[
        MaterialRoute(
          page: MainApp,
          name: 'group',
          path: '/groups',
          children: <MaterialRoute>[
            MaterialRoute(
              page: ViewGroupInDetailPage,
              name: 'groupInDetail',
              path: '/:groupId',
              children: <MaterialRoute>[
                MaterialRoute(
                  page: ViewPostInDetailPage,
                  name: 'postInDetail',
                  path: '/posts/:postId',
                  children: <MaterialRoute>[
                    MaterialRoute(
                      page: PostFormPage,
                      name: 'editPost',
                      path: '/edit',
                    ),
                  ],
                ),
                MaterialRoute(
                  page: EditGroupPage,
                  name: 'editGroup',
                  path: '/edit',
                  children: <MaterialRoute>[
                    MaterialRoute(
                      page: EditGroupMembersPage,
                      name: 'editGroupUsers',
                      path: '/members',
                    ),
                    MaterialRoute(
                      page: EditGroupMembersPage,
                      name: 'editGroupModerators',
                      path: '/moderators',
                    ),
                  ],
                ),
              ],
            ),
          ],
        ),
      ],
    ),
  ],
)
class $CustomRouter {}

It's probably only something small I missed. Thanks for the help.

Milad-Akarie commented 3 years ago

Could you share your material App setup?

McCrafterIV commented 3 years ago

Sure

MaterialApp(
  localizationsDelegates: [
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    localizationDelegate
  ],
  supportedLocales: localizationDelegate.supportedLocales,
  locale: localizationDelegate.currentLocale,
  theme: ThemeData(
    primarySwatch: Colors.grey,
  ),
  builder: ExtendedNavigator(
    router: AppRouter(),
  ),
),

I've done further testing and found a solution myself. For every route with children, I added a route with the same properties, except for the name and the initial property set to true, as a child:

MaterialRoute(
  page: ViewPostInDetailPage,
  name: 'postInDetail',
  path: '/posts/:postId',
  children: <MaterialRoute>[
    MaterialRoute(
      page: ViewPostInDetailPage,
      initial: true,
    ),

    ... // the other child routes

 ],
)

This solution works in general, but it doesn't seems to me as if it would be the ideal solution. Also the app malfunctions and I need to take the time to investigate if this is only an error on my side or if this solution isn't usable for some reason. I wanted to achieve a routing system, where I can dynamically jump to a sub-route without the need to pass in all the other variables used before in the routing path. What I mean by that: I have two paths. The first path for viewing a post /posts/:id and the second for editing the same post /posts/:id/edit. My goal was to be able to edit a post (jump to the path /posts/:id/edit), when I'm currently viewing a post (in other words accessing the path /posts/:id) without the need to pass the :id parameter again, because this can get complicated when working with multiple parameters from different data sources. My idea was to use nested routes, like seen above, but is this the best solution? Or is there another or no option to achieve my goal.

Thanks for the help

Milad-Akarie commented 3 years ago

@McCrafterIV you need to switch to the new router setup if you're dealing with nested routes https://pub.dev/packages/auto_route/versions/1.0.0-beta

McCrafterIV commented 3 years ago

Thanks for the answer! I switched to the new setup and it works, kind of. I partially changed my router annotation (see below) and the app starts. But when I try to push to the route groups/ID I get the following error and I can't figure out why.

E/flutter ( 6904): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: [ROOT Router] can not navigate to groups/vudxAeyhWqe8xTASe48rDe
E/flutter ( 6904): #0      RouterNode._resolveConfigOrReportFailure (package:auto_route/src/router/controller/routing_controller.dart:348:9)
E/flutter ( 6904): #1      RouterNode._push (package:auto_route/src/router/controller/routing_controller.dart:193:18)
E/flutter ( 6904): #2      RouterNode.push (package:auto_route/src/router/controller/routing_controller.dart:183:12)
....

To push the route, I use

context.router.push(
  GroupInDetailPage(
    groupId: group.id,
  ),
);

Is my configuration wrong or did I miss something? Here is my slightly changed annotation:

@MaterialAutoRouter(
  routes: <AutoRoute>[
    AutoRoute(
      page: SplashPage,
      name: 'splashPage',
      initial: true,
    ),
    AutoRoute(
      page: SignInPage,
      name: 'signInPage',
      path: '/sign-in',
    ),
    AutoRoute(
      page: MainApp,
      path: '/app',
      name: 'app',
      children: <AutoRoute>[
        AutoRoute(
          page: ViewGroupInDetailPage,
          name: 'groupInDetailPage',
          path: 'groups/:groupId',
          children: <AutoRoute>[
            AutoRoute(
              page: ViewPostInDetailPage,
              name: 'postInDetailPage',
              path: 'posts/:postId',
              children: <AutoRoute>[
                AutoRoute(
                  page: PostFormPage,
                  name: 'editPostPage',
                  path: 'edit',
                ),
              ],
            ),
            AutoRoute(
              page: EditGroupPage,
              name: 'editGroupPage',
              path: 'edit',
              children: <AutoRoute>[
                AutoRoute(
                  page: EditGroupMembersPage,
                  name: 'editGroupUsersPage',
                  path: 'members',
                ),
              ],
            ),
          ],
        ),
      ],
    ),
  ],
)
class $CustomRouter {}
Milad-Akarie commented 3 years ago

That makes sense. The target page ia inside of another root page, If you're to do this using a path you'd push '/app/group/id'

Using route objects router.push(AppRoute(children:[ GroupRoute(id:...) ]))

McCrafterIV commented 3 years ago

That sounds right to me and I will test this soon. One question remains, is there an option to push (like I mentioned before) from route /app/groups/:id to /app/groups/:id/edit without again providing the id variable again? This is what I originally wanted to achieve using this setup.

Milad-Akarie commented 3 years ago

You could access the parent route from inside of your edit page like follows

context.route.parent.pathParams Or of you want the typed value ..parent.getArgs<GroupRouteArgs>().groupId

I'm replying from my phone.. excuse the mess.

McCrafterIV commented 3 years ago

Thanks for the quick help. I will try these solutions soon and close the issue then, if my problems are solved. Thanks for the great package!

Milad-Akarie commented 3 years ago

You're welcome. One more tip, The name property represents the PageRouteObject's name so it should be upper camel-cased

McCrafterIV commented 3 years ago

Thanks for the tip. I'll change that too :)

firatcetiner commented 3 years ago

@Milad-Akarie I guess we can't use something like pushNamed in the latest version 1.0.0-beta? The route paths aren't visible, I can only access view's name so I have to use context.router.push(PageRouteObject()) instead of using context.router.pushPath(path). In the current stable channel the route paths are generated inside the generated router file, now its gone. Also, I could't find any method that I can pass arguments.

Milad-Akarie commented 3 years ago

@firatcetiner you shouldn't need to use strings, the generated RouteObject acts as an identifier and an args holder. push(ProductDetailsRoute(id: 1)); Think of this as adding an event to a bloc or a strore.

firatcetiner commented 3 years ago

@firatcetiner you shouldn't need to use strings, the generated RouteObject acts as an identifier and an args holder. push(ProductDetailsRoute(id: 1)); Think of this as adding an event to a bloc or a strore.

Interesting. Can you add a full example of how to use version 1.0.0-beta with Flutter's new navigation system? Since the usage of MaterialApp.router is a must for this version, we cannot use the features of Navigator anymore. For example I cannot use showDialog because it uses Navigator.

Milad-Akarie commented 3 years ago

@firatcetiner you have little documentation here https://pub.dev/packages/auto_route/versions/1.0.0-beta.9 and two examples here https://github.com/Milad-Akarie/auto_route_library/tree/master/auto_route/example/lib

firatcetiner commented 3 years ago

Thanks for the quick answer but it seems it is now impossible to utilize nested navigators using this library, while using core Navigator features. Thanks again!

Milad-Akarie commented 3 years ago

@firatcetiner the new auto_route has a better handling for nested navigators... what are you trying achieve?

firatcetiner commented 3 years ago

@Milad-Akarie I have simple bottom navigation bar and I want to use nested navigators, ExtendedNavigator would not work so I had to continue wirh 1.0.0-beta. To use the new version, obsiously I had to use MaterialApp.router instead of default MaterialApp but the drawback is I cannot use Navigator anymore. For example Flutter uses Navigator to display dialogs and bottom sheets and I can't use them anymore. Also parsing arguments was easy as ModalRoute.of(context).settings.arguments but It is now gone too, with the new auto_route version. Parsed arguments are always null, strangely.

I used AutoTabsRouter also in the new version.

firatcetiner commented 3 years ago

Hey, @Milad-Akarie I have managed to implement nested routes with the current stable version of auto_route. Using the ExtendedNavigator, I had to pass the onUnknownRoute explicitly so that it can find the initial route for the nested route.

Here is an abstraction:

ExtendedNavigator(
      navigatorKey: GlobalKey<NavigatorState>(),
      initialRoute: Routes.myCustomView,
      router: MyCustomRouter(),
      onUnknownRoute: (_) => CupertinoPageRoute(
        builder: (_) => MyCustomView(),
            ),
      },
),

Maybe this workaround can help others who cannot afford to update version 1.0.0-beta yet.