AlexxNB / tinro

Highly declarative, tiny, dependency free router for Svelte's web applications.
MIT License
669 stars 30 forks source link

get current route path with parameters #32

Closed sallaben closed 3 years ago

sallaben commented 3 years ago

Is there a way to get the current route path (not url path) from the writable store?

Right now, the value stored is of format {path, query, hash}, where the path value contains the current url path, e.g. /accounts/12345

I am looking for the route path value, e.g. /accounts/:account

AlexxNB commented 3 years ago

I didn't add this to the router output. But it is easy to add. But what is use case? Just interesting =)

sallaben commented 3 years ago

I would like to use it to implement router and route guards programmatically: (the code is not fully optimized yet)

<script>
  import { Route, router } from 'tinro';

  export let routes;
  export let prefix = '';

  router.subscribe(({ route }) => {
    const match = routes.find((r) => r.path === route);
    if (match && match.guard) {
      const permitted = match.guard.evaluate();
      if (!permitted) {
        router.goto(match.guard.redirect);
      }
    }
  });
</script>

{#each routes as route}
  <Route path={route.path} let:params>
    {#if route.children}
      <svelte:self 
        routes={route.children} 
        prefix={`${prefix}${route.path}`} />
    {:else}
      <main>
        <svelte:component this={route.component} {params} />
      </main>
    {/if}
  </Route>
{/each}

The routes can now be supplied like this

const routes = [
  {
    path: '/',
    component: HomeRoute,
  },
  {
    path: '/login',
    component: LogInRoute,
    guard: guards.mustBeLoggedOut,
  },
  {
    path: '/accounts/*',
    children: [
      {
        path: '/',
        component: AccountsRoute,
        guard: guards.mustBeLoggedIn,
      },
      {
        path: '/:account/*',
        children: [
          {
            path: '/',
            component: AccountRoute,
            guard: guards.mustBeLoggedIn,
          },
          {
            path: '/dashboard',
            component: DashboardRoute,
            guard: guards.mustBeLoggedIn,
          },
        ],
      },
    ],
  },
];

And the guards

const guards = {
  mustBeLoggedIn: {
    evaluate: () => isLoggedIn,
    redirect: '/login',
  },
  mustBeLoggedOut: {
    evaluate: () => !isLoggedIn,
    redirect: '/',
  },
};
AlexxNB commented 3 years ago

Looks like you are making config-based router from the declarative one. Maybe better to take one of the config-router instead - like https://github.com/easyroute-router/svelte-easyroute

sallaben commented 3 years ago

Thanks for the suggestion. I tried svelte-easyroute, and unfortunately I have found that it does not fit my needs. There are a few bugs in the implementation of history mode that I can't seem to get around (I'm working on a GH issue for the author).

I would still like to use tinro to create my own config based router, since your implementation does exactly what it says on the tin, no curious behavior or complicated APIs. If I were to fork your repo and make the change to include this route value in the store, which files should I look in?

sallaben commented 3 years ago

I bit the bullet and switched to declarative style. I will let you know if that prevents me from doing anything but thank you anyway!