Svelte Event Router

A simple SPA router that enforces event-driven user interfaces. Your router does a lot for you. Choose a good one.

Why This One

Rather than navigating to a URL to update the view (while this does work), you send events to the router. Event driven development results in well-architected projects that are predictable and less prone to errors.

npm install svelte-event-router

Getting Started

To get started, import Router and specify your views.

<div class="container">
    <Router
        initial="signin"
        {views}
    />
</div>

<script>
import Router from "svelte-event-router";

// Views
import signin from "./views/signin.svelte";
import signup from "./views/signup.svelte";

const views = { 
    signin, // url.com/#/signin                      
    signup, // url.com/#/signup                        
};
</script>

Sending Events

Events allow you to communicate with a router instance. Events are used to update the current view, or communicate with other services.

The Send Method

The send method is passed in as a prop to all views as well as exported from the Router component. To update the current router view, send an event that matches the name of one of your views. If a view isn't matched to the event name, the router will stay where it is and nothing will happen.

send([ Event Name (String) ], [ Optional Payload (Any) ]);

Within a View

<button on:click="{() => send('signup')}">Go to Signup</button>

<script>
export let send;
</script>

Outside a View

<div class="container">
    <Router
        initial="signin"
        bind:send="{send}"
        {views}
    />
    <button on:click="{() => send('signup')}">Go to Signup</button>
</div>

<script>
import Router from "svelte-event-router";

// Views
import signin from "./views/signin.svelte";
import signup from "./views/signup.svelte";

let send;

const views = { 
    signin, // url.com/#/signin                      
    signup, // url.com/#/signup                        
};
</script>

Router Store

Subscribing to the router store allows you take action when certain events occur. The router store updates on page load and whenever an event is sent via the the "send()" method. Like the send method, the router store is also passed in as prop to every view as well as exported to the Router component.

{
    data,        // Payload from the last event.
    event,       // Name of the last event.
    _event,      // Two events ago.
    current,     // Current view. Only updates when view changes.
    params,      // A JavaScript Map of URL parameters.
} = $router

Within a View

<script>
export let router;
</script>

Outside a View

<Router
    initial="signin"
    bind:router="{router}"
    {views}
/>


<script>
import Router from "svelte-event-router";

// Views
import signin from "./views/signin.svelte";
import signup from "./views/signup.svelte";

const views = { 
    signin, // url.com/#/signin                      
    signup, // url.com/#/signup                        
};

let router;

// Wait for router to be ready
$: if($router) {
    // Code to run on any router update
}
</script>

Custom event listeners

Sometimes events are used to trigger other actions besides updating the view. Here we are sending a "submit" event. Since it doesn't match up with the name of a view, the router won't update the view but it will still update the router store.

<form on:submit="{() => send('submit', { user })}"></form>

<script>
export let send;
</script>
<Router
    initial="signin"
    bind:router="{router}"
    {views}
/>


<script>
import Router from "svelte-event-router";

// Views
import signin from "./views/signin.svelte";
import signup from "./views/signup.svelte";

let router;

const views = { 
    signin, // url.com/#/signin                      
    signup, // url.com/#/signup                        
};

const myFunction = (user) => {  };

// Wait for the router to be ready,
// run our function if the last event was "submit",
// pass in the payload from the last "submit" event.
$: if($router) {
    $router.event === "submit" && myFunction($router.data);
}
</script>

Consuming URL Parameters

The router store searches for any URL parameters and formats them as a JavaScript Map.

<Router
    initial="signin"
    bind:router="{router}"
    {views}
/>

<script>
import Router from "svelte-event-router";

// Views
import signin from "./views/signin.svelte";
import signup from "./views/signup.svelte";

let router;

const views = { 
    signin, // url.com/#/signin                      
    signup, // url.com/#/signup                        
};

const loadPost = (id) => {  };

// Wait for the router to be ready,
// check if URL parameter exists,
// and pass it into our function.
$: if($router) {
    $router.params.has("id") && loadPost(params.get("id"));
};
</script>

Utilizing Current

Here's an example of a simple nav that highlights the button corresponding to the active view.

<Router
    initial="signin"
    bind:router="{router}"
    bind:send="{send}"
    {views}
/>

<button
    on:click="{() => send('signin')}"
    style="text-decoration: {$router.current === 'signin' ? 'underline' : 'none'}"
>
Sign In
</button>
<button
    on:click="{() => send('signup')}"
    style="text-decoration: {$router.current === 'signup' ? 'underline' : 'none'}"
>   
Sign Up
</button>

<script>
import Router from "svelte-event-router";

// Views
import signin from "./views/signin.svelte";
import signup from "./views/signup.svelte";

let router;
let send;

const views = { 
    signin, // url.com/#/signin                      
    signup, // url.com/#/signup                        
};
</script>