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

hash link might sometimes break the navigation #2208

Open
eslym opened this issue Jan 24, 2025 · 2 comments
Open

hash link might sometimes break the navigation #2208

eslym opened this issue Jan 24, 2025 · 2 comments

Comments

@eslym
Copy link

eslym commented Jan 24, 2025

Versions:

  • @inertiajs/core version: 2.0.3
  • @inertiajs/svelte version: 2.0.3

Describe the problem:

any <a href="#anyhash">hello world</a> will sometimes cause the window.history.state become null, then the later visit will failed
but handle the click with inertia will cause unecessary network request, the hashchange event does not fire thanks to history.pushState

Steps to reproduce:

  1. <a href="#1">hello world 1</a> <a href="#2">hello world 2</a>
  2. navigate around (not guaranteed to trigger, but chance is quite high)

Image

my workaround (svelte 5)

import { createSubscriber } from 'svelte/reactivity';
import { on } from 'svelte/events';
import { router } from '@inertiajs/svelte';

const subscribe = createSubscriber((update) => {
    return on(window, 'hashchange', update);
});

export const fragment = {
    get value() {
        subscribe();
        return window.location.hash;
    },
    set value(value) {
        if (!value.startsWith('#')) {
            value = '#' + value;
        }
        if (value !== window.location.hash) {
            const newUrl = new URL(value, window.location.href);

            // inertia uses replace state internally when there is only hash changed, which is not really same as browser behaviour
            router.push({
                url: newUrl.href
            });

            window.dispatchEvent(new HashChangeEvent('hashchange'));
        }
    }
};

export function replaceHash(value: string) {
    if (!value.startsWith('#')) {
        value = '#' + value;
    }
    if (value !== window.location.hash) {
        const newUrl = new URL(value, window.location.href);
        router.replace({
            url: newUrl.href
        });
        window.dispatchEvent(new HashChangeEvent('hashchange'));
    }
}

document.body.addEventListener('click', ((event: MouseEvent & { target: HTMLAnchorElement }) => {
    if (
        event.defaultPrevented ||
        event.button !== 0 ||
        event.ctrlKey ||
        event.metaKey ||
        event.shiftKey ||
        event.target.tagName !== 'A' ||
        event.target.target === '_blank'
    )
        return;
    const url = new URL(event.target.href);
    if (
        url.origin === window.location.origin &&
        url.pathname === window.location.pathname &&
        url.search === window.location.search &&
        url.hash !== window.location.hash
    ) {
        event.preventDefault();
        fragment.value = url.hash;
    }
}) as any);

p/s: browser will push to history when hash changed, so this line really shouldn't be there

replace = replace || isSameUrlWithoutHash(hrefToUrl(page.url), location)

@stevebauman
Copy link

@eslym Do these links possibly have a @click handler associated with them?

@eslym
Copy link
Author

eslym commented Feb 2, 2025

@eslym Do these links possibly have a @click handler associated with them?

no, even newly setup project having this issue

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

2 participants