route.dart icon indicating copy to clipboard operation
route.dart copied to clipboard

`null` in the URL if `path` is not specified for a route

Open antonmoiseev opened this issue 10 years ago • 4 comments

Consider I want to have the following hierarchy of routes in my app:

  1. /products - is the common URL for all product-related pages. Serves page with all available items listed. Naturally it should become a parent route for page-specific mounted sub-routes.
  2. /products/:id - should become a mounted route of /products and display product details page.

1. Straightforward approach

Straightforward routing configuration would look like this:

_initRouter(Router router, RouteViewFactory views) {
    views.configure({
        'product': ngRoute(
            path: '/products',
            view: 'views/products.html',
            modules: () => [new ProductModule()],
            mount: {
                'details': ngRoute(
                    path: '/:id',
                    view: 'views/product_details.html')
            })
    });
}

But as we found out, a route with mounted routes, always displays its own view, mounted routes' views are never displayed. And this is by design.

2. Flattening routes

What are available workarounds?! Flatten the route hierarchy:

_initRouter(Router router, RouteViewFactory views) {
    views.configure({
        'product_list': ngRoute(
            path: '/products',
            view: 'views/products.html',
            modules: () => [new ProductModule()]),
        'product_details': ngRoute(
            path: '/products/:id',
            view: 'views/product_details.html',
            modules: () => [new ProductModule()])
    });
}

But this way I have my modules instantiated twice. All the services that are expected to be singletons now have multiple instances and can't be used to share the data. To workaround the workaround I would need to cache the module instances. And generally flattening kills the idea of structuring your routes using route hierarchies.

3. Third take

Turns out there is an elegant solution. If we set defaultRoute: true for a mounted route, we can host its view on the parents URL:

_initRouter(Router router, RouteViewFactory views) {
    views.configure({
        'product': ngRoute(
            path: '/products',
            viewHtml: '<ng-view></ng-view>',
            modules: () => [new ProductModule()],
            mount: {
                'list': ngRoute(
                    defaultRoute: true,
                    view: 'views/products.html'),
                'details': ngRoute(
                    path: '/:id',
                    view: 'views/product_details.html')
            })
    });
}

Now everything looks good, we leverage the routes hierarchy to avoid duplicating common path parts and dependent modules declaration, have a single instance of each dependent module created and fully satisfy original requirements - don't have any redundant sub-paths (i.e. adopting this approach would lead to a redundant sub-path /products/list)

Finally we come closer to the originally reported issue :). If we use the latest configuration we have null inside the URL when we try to navigate to product.list route using Router's go() method:

router.go('product.list') // => http://localhost:8080/productsnull

Right now to workaround this behavior we can add path to the product.list route configuration:

// configuration
'list': ngRoute(
    defaultRoute: true,
    path: '',
    view: 'views/products.html')

// usage
router.go('product.list') // => http://localhost:8080/product

or:

// configuration
'list': ngRoute(
    defaultRoute: true,
    path: '/',
    view: 'views/products.html')

// usage
router.go('product.list') // => http://localhost:8080/product/

In the last example we must have defaultRoute: true defined, otherwise users won't be able to navigate to the product list page if they forget to type / at the end of the URL in the browser's address bar.

antonmoiseev avatar Aug 15 '14 12:08 antonmoiseev

Basically path is required, and ngRoute should complain if path is not provided.

pavelgj avatar Aug 15 '14 13:08 pavelgj

@antonmoiseev Thank you for all the detailed issues you've been posting. I'm tearing my hair out trying to figure out Angular.dart routing, and after reading several of your issues, I am finally starting to figure it out.

mehaase avatar Mar 14 '15 03:03 mehaase

You are welcome! BTW, we ended up flattening all our routes. We experienced an issue with navigation when typing in URL manually in the address bar and with blank pages in IE 10 and above.

antonmoiseev avatar Mar 16 '15 12:03 antonmoiseev

I tried flattening my routes this morning and already a lot of the strange behavior is gone! (Particularly the watchQueryParameters, which I couldn't get to work correctly on a nested route.) Thank you again.

mehaase avatar Mar 16 '15 16:03 mehaase