Sebastian S.
Sebastian S.

Reputation: 31

Svelte - communicate between pages and components without include it directly

I have a little problem in Svelte, maybe someone else hit this thing.

I structured the application as follows:

In _layout.svelte I imported a Banner component. Here I should have the title and description of each page I browse.

If I'm on the first page, send the title and description to the banner component, if I'm on the page about the same thing to happen.

The idea is that the pages don't import this component, so they don't really communicate with each other.

Do you have any idea how I could proceed?

Thanks!

Upvotes: 3

Views: 1047

Answers (2)

itnelo
itnelo

Reputation: 1103

I should admit that the Stephane's answer is the most convenient to the date (I had a similar problem), but there are also event systems - Svelte-based or DOM-based. You can setup a decoupled communication between components without any static relations.

Since you are not building any component hierarchy in this use-case, the DOM events can be used instead:

Banner.svelte

<script type="text/javascript">
    import { onMount } from 'svelte';

    let title = '';

    function onTitleUpdated(customEventWithTitle) {
        title = customEventWithTitle.detail;
    }

    onMount(
        function () {
            document.addEventListener("titleUpdated", onTitleUpdated);

            return () => {
                document.removeEventListener("titleUpdated", onTitleUpdated);
            }
        }
    );
</script>

<h1>{title}</h1>

AboutPage.svelte

<script type="text/javascript">
    function onClick() {
        const titleUpdatedEvent = new CustomEvent("titleUpdated", {detail: "new title"});

        document.dispatchEvent(titleUpdatedEvent);
    }
</script>

REPL: https://svelte.dev/repl/6f373acad4be4aad95f3340bc53d9bc2

But beware: if you've decided to use a Svelte-based way from the documentation, at this point (3.35) there are no way to forward an event though a "third-party" component (i.e. from the external library), see here. I wish we will have an event-forwarding directive similar to $$restProps, something like $$restEvents so an event can bubble through the third-party components, which are not in our "area of responsibility".

Upvotes: 1

Stephane Vanraes
Stephane Vanraes

Reputation: 16411

There are several ways to do this

One is to actually handle this in _layout.svelte using the current path (but this is very limited as the layout would need to know about all possible pages)

Another is to export a function or store from the Banner module that allows to set this.

<!-- Banner.svelte -->
<script context="module">
  import { writable } from 'svelte/store'
  export const title = writable('')
</script>

<h1>{$title}</h1>
<!-- AboutPage -->
<script>
  import { title } from 'Banner.svelte'
  title.set('About')
</script>

The third way would be to setup a very similar construct but have the store in the layout file and make it available to all descendants (both the Banner and the xxxPage component) using set/getContext instead.

My preference would go out to the second option (the exported store) as it is the most straightforward one.

Upvotes: 3

Related Questions