kruschid / typesafe-routes

Spices up your favorite routing library by adding type safety to plain string-based route definitions.
https://kruschid.github.io/typesafe-routes/
MIT License
102 stars 8 forks source link

Angular - Optional parameters aren't counted as parameters #35

Closed Indeedornot closed 2 weeks ago

Indeedornot commented 1 year ago

Issue

When using this library with Angular and making parameters optional e.g.

    public static orders = {
        show: route('orders/:id?', { id: intParser }, {})
    };

and registering such route as so

const routes = [
    // Orders
    {
        path: AppRoutes.orders.show.template,
        component: OrdersPageComponent
    }
}

the route is indentified as so orders/:id where :id is a string rather than a parameter

Possible workaround

Using a preprocessing function that preprocesses the paths before giving them to Angular to register

const getRoute = (route: RouteNode<string, any, any>) => {
    //remove all instances of '?' from route
    if (route.template.includes('?')) {
        return route.template.replace(/\?/g, '');
    }

        return route.template;
}

and using it instead of the clear template

const routes = [
    // Orders
    {
        path: getRoute(AppRoutes.orders.show),
        component: OrdersPageComponent
    }
}

Possible solutions

1. Implementing the preprocessing function in the core

2. Moving the optional declaration onto the ParserMap e.g.

    public static orders = {
        show: route('/orders/:id', { id?: intParser }, {})
    };
kruschid commented 3 weeks ago

I'm not very familiar with optional parameters in Angular. However, if you're suggesting that it's possible to leave a parameter undefined that is specified in a template, then it could potentially be solved with a custom template rendering function. However, this would require an upgrade to version 12.

Consider the renderTemplate function from the Angular Router example given here. The returned templates don't have optional parameters with a trailing ? character.

const renderTemplate = ({ pathSegments }: AnyRenderContext) => {
  const template = pathSegments
    .map((pathSegment) =>
      typeof pathSegment === "string" ? pathSegment : `:${pathSegment.name}`
    )
    .join("/");

  return template; // path that doesn't start with a slash "/" character
};

You can refer to this documentation on how to use custom rendering functions.

Thanks for the feedback.