Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Access path in other components #41

Closed
eduarddotgg opened this issue Jun 1, 2019 · 12 comments
Closed

Access path in other components #41

eduarddotgg opened this issue Jun 1, 2019 · 12 comments

Comments

@eduarddotgg
Copy link

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?

@EmilTholin
Copy link
Owner

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.

@eduarddotgg
Copy link
Author

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

@EmilTholin
Copy link
Owner

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

@eduarddotgg
Copy link
Author

eduarddotgg commented Jun 4, 2019

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.

@kysonic
Copy link

kysonic commented Jun 19, 2019

@iamfrntdv How about the following approach?

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

$: {
    console.log($activeRoute)
 }

@eduarddotgg
Copy link
Author

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

@LaughingBubba
Copy link

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

@henk23
Copy link

henk23 commented Feb 14, 2021

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.

@kryptus36
Copy link
Collaborator

@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
Copy link
Collaborator

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 .

@krishnaTORQUE
Copy link
Collaborator

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

@jeffersoncostas
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants