ItalyPaleAle / svelte-spa-router

Router for SPAs using Svelte 3
MIT License
1.53k stars 105 forks source link

Back button but only if inside the app #286

Closed emarj closed 1 year ago

emarj commented 1 year ago

This is not exactly an "issue" but more of a question. I've looked around but didn't find a solution for this.

I currently have a "back" button that calls pop(). The issue is that this can potentially send you outside the application. I would like to show this button only if the previous page is inside my application.

Is there a way to do this?

Does the router internally keeps an "history stack" or it just uses the browser history? In the first case would be easy to just check if the stack is empty (that is, if the previous page was outside application).

Maybe one can construct such a "stack" by using routeLoading/routeLoaded events but would be nice to have an easier way.

Thanks

EDIT: I was able to quickly hack together what I need, it works, but it is a bit sketchy and far from solid.

export const historyStore = writable({ stack: [], aboutToPop: false });
function routeLoaded(event) {
    historyStore.update((data) => {
      if (!data.aboutToPop) {
        data.stack.push(event.detail.route);
      } else {
        data.aboutToPop = false;
      }
      return data;
    });
  }
{#if $historyStore.stack.length > 1}
        <button
            on:click={() => {
                historyStore.update((data) => {
                    data.stack.pop();
                    data.aboutToPop = true;
                    return data;
                });
                pop(); //this will trigger routeLoaded but since we set aboutToPop to true we will ignore it
            }}
            >← Back
        </button>
    {/if}
emarj commented 1 year ago

I understand this might not be want we want since the app behavior will depend on which back button (the browser or the app one is used). My idea was to use this in a PWA app where the history buttons are not showed to the client. On the other hand, I realize now, that in this setting usually there is no real danger of "exiting" the application since the app was directly loaded and not accessed via a link in the browser, so the history should be clean when we first load the app.

Nonetheless, it would be nice for the back button to be at least be greyed out (or invisible) when we first load the app.

ItalyPaleAle commented 1 year ago

The router uses the browser's own history stack, and sadly what you're asking for is not possible. The reason is that JS apps cannot actually see what's in the history stack, but can only ask the browser to go back (or forward); being able to know where a user was before would be too much of a privacy issue.

Although your approach could work, the problem with it is that it won't survive a reload of the page: because the stack is kept in the page's state, if the user reloads the page, it will be gone. That's also the reason why the router doesn't implement a custom history stack like that.

I'm going to close this as there's really nothing we can do here, I'm afraid :(