svelte-routing icon indicating copy to clipboard operation
svelte-routing copied to clipboard

Access path in other components

Open eduarddotgg opened this issue 5 years ago • 10 comments

Is there any way to access/watch current path in components that are available in all routes for example header. I would like to show different links based on current path.

<Router url="{url}">
<AppHeader>
  <div>
    <Route path="/welcome" component="{Welcome}" />
    <Route path="/login" component="{Login}" />
  </div>
</Router>

<!-- AppHeader -->
<header>
  <nav>
  {#if currentPath != '/login' }
    <Link to="/login">Login</Link>
  {:else}
  <Link to="/welcome">Go Back</Link>
{/if}
  </nav>
</header>

Is there any preferred way to day this?

eduarddotgg avatar Jun 01 '19 07:06 eduarddotgg

Hi @iamfrntdv!

There is currently no nice way to do this. We could possibly take some more inspiration from Reach Router and give the location object as a property to the rendered component, but that would not work in your example.

We could possibly expose createHistory and createMemoryHistory and give the Router a new history prop, so that you could supply a history of your own that you can read from and listen to, much like the LocationProvider functionality in Reach Router.

EmilTholin avatar Jun 03 '19 08:06 EmilTholin

How about creating global state or variable so it will be available everywhere, something like vue-router does?

eduarddotgg avatar Jun 03 '19 20:06 eduarddotgg

Interesting. I have very limited experience with vue-router, and I'm not exactly sure what behaviour you are referring to. Could you elaborate?

EmilTholin avatar Jun 04 '19 07:06 EmilTholin

Vue Router creates global object/state (accessible everywhere) which updates every time path changes. Here you can see what else is available: Screenshot 2019-06-04 at 9 51 37 in this case it shows what is current active path and what name, params, queries, meta it has.

eduarddotgg avatar Jun 04 '19 08:06 eduarddotgg

@iamfrntdv How about the following approach?

import {getContext} from 'svelte';
import {ROUTER} from 'svelte-routing/src/contexts';
const { activeRoute } = getContext(ROUTER);

$: {
    console.log($activeRoute)
 }

kysonic avatar Jun 19 '19 08:06 kysonic

@kysonic hmmm, this may work. I'll try it and let you know. Thanks.

eduarddotgg avatar Jun 19 '19 12:06 eduarddotgg

Thanks @kysonic, your solution works fine for me.

I moved my <navbar> component to be in scope of the <Router>

<Router>
	<NavBar isLoggedIn={isLoggedIn} loggedInUser={loggedInUser} />
	<Route exact path="/">
		<Home isLoggedIn={isLoggedIn} loggedInUser={loggedInUser} />
	</Route>
	<Route path="/panels" component={Panels} />
	<Route path="/users" component={Users} />
	<Route path="/login" component={Login} />

	<Route path="*" component={NotFound} />
</Router>

Then on the <NavBar> component:

<script>
  import { getContext } from 'svelte'
  import { ROUTER } from 'svelte-routing/src/contexts'
  var { activeRoute } = getContext(ROUTER)
   ...
</script>

<main>
    ...
    {#if !isLoggedIn && ($activeRoute ? $activeRoute.uri : '') != '/login'}
      <button type="button" on:click={()=>navigate('/login')}>Login</button>
    {:else if isLoggedIn}
      <span >{loggedInUser.displayName ? loggedInUser.displayName : ''}</span>
      <button type="button" on:click={logout} outline>Logout</button>
    {/if}
   ...
</main>

This way the the login button doesn't get displayed on the <navbar> when the user is on the \login route

LaughingBubba avatar Jan 08 '20 10:01 LaughingBubba

I have another workaround for when you are in the topmost component, so getContext() does not work (because you don't have a parent <Router/> component):

<script>
  import {Router, Route} from 'svelte-routing';
  import {globalHistory} from 'svelte-routing/src/history';
  import {route} from './stores.js';

  $route = globalHistory.location;

  globalHistory.listen(history => {
    $route = history.location;
  });
</script>

<Router>
  <!-- other routes... -->
  <Route path="/" component={Home}/>
</Router>

{#if $route.pathname === '/'}
  <img src="logo-home.svg">
{:else}
  <img src="logo-general.svg">
{/if}

This way you have the variable $route in a global store and can access it from anywhere in your app.

henk23 avatar Feb 14 '21 11:02 henk23

@kysonic @henk23 Do these methods still work for you? When I try to use ROUTER context its undefined (I am inside the router context when trying it, in fact have tried moving it all over.)

When I try the globalHistory.listen method I seem to end up with 2 instances of globalHistory and my listener doesn't get called. I don't know how that is even possible.

I have a router embedded in another router, though looking at the code I think this should be fine. If anyone has insight, it'd be appreciated.

kryptus36 avatar Mar 11 '22 21:03 kryptus36

I found a solution in case anyone runs into the same issue. It's a bundler problem.

The router was using globalHistory from one place but when I directly imported import {globalHistory} from 'svelte-routing/src/history';

My bundler was grabbing it from a different place. The solution was to add globalHistory to the exports for svelte-routing and import it from there .

kryptus36 avatar Mar 11 '22 23:03 kryptus36

Svelte Routing v1.8 has been released, which added useLocation hook, by using it you can track if location or route changes.

krishnaTORQUE avatar May 05 '23 14:05 krishnaTORQUE

@krishnaTORQUE How can i use the useLocation hook? It does not react to changes and gives me undefined everytime

jeffersoncostas avatar Jul 29 '23 18:07 jeffersoncostas