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

$page.url.hash is not updated. #9374

Closed
hyunbinseo opened this issue Mar 9, 2023 · 4 comments · Fixed by #10202
Closed

$page.url.hash is not updated. #9374

hyunbinseo opened this issue Mar 9, 2023 · 4 comments · Fixed by #10202
Labels
bug Something isn't working low hanging fruit ready to implement please submit PRs for these issues!
Milestone

Comments

@hyunbinseo
Copy link
Contributor

hyunbinseo commented Mar 9, 2023

Describe the bug

When the URL hash value is changed using the address bar, the $page store is not updated.

Reproduction

Checked on Chrome, Firefox, and Safari. Reference 'System Info' for version numbers.

<script>
  import { page } from '$app/stores';
  
  $: console.log($page.url.hash);
</script>

<svelte:window
  on:hashchange={() => {
    console.log($page.url.hash, 'store');
    console.log(window.location.hash, 'location')
  }}
/>

<a href="#1">#1</a>
  1. Load the page
  2. Click the anchor element.
  3. Replace #1 with #2 in the address bar.
  4. Check the console.
<!-- Anchor is clicked. Hash is now #1 -->
#1
#1 store
#1 location

<!-- URL is updated. Hash is now #2 -->
#1 store
#2 location

Logs

No response

System Info

System:
  OS: macOS 13.2.1
  CPU: (8) arm64 Apple M1
  Memory: 78.86 MB / 8.00 GB
  Shell: 5.8.1 - /bin/zsh
Binaries:
  Node: 18.14.1 - ~/.nvm/versions/node/v18.14.1/bin/node
  npm: 9.3.1 - ~/.nvm/versions/node/v18.14.1/bin/npm
Browsers:
  Chrome: 110.0.5481.177
  Firefox: 110.0
  Safari: 16.3
npmPackages:
  @sveltejs/adapter-auto: ^2.0.0 => 2.0.0 
  @sveltejs/kit: ^1.5.0 => 1.11.0 
  svelte: ^3.54.0 => 3.55.1 
  vite: ^4.0.0 => 4.1.4

Severity

annoyance

Additional Information

No response

@vicentematus
Copy link
Contributor

vicentematus commented Mar 23, 2023

@Rich-Harris Just to brainstorm: one of the ways to deal with this is to update instances of the stores of page and url whenever the event hashchanges is emitted?

addEventListener('hashchange', () => {
// if the hashchange happened as a result of clicking on a link,
// we need to update history, otherwise we have to leave it alone
if (hash_navigating) {
hash_navigating = false;
history.replaceState(
{ ...history.state, [INDEX_KEY]: ++current_history_index },
'',
location.href
);
}
});

This is where the magic should happen? 🤔

Accessing the stores via:

export const stores = {
url: notifiable_store({}),
page: notifiable_store({}),
navigating: writable(/** @type {import('types').Navigation | null} */ (null)),
updated: create_updated_store()
};

I've seen the other pr's related to the hashchange event like #3177 but can't see through the problem yet 👀

@vicentematus
Copy link
Contributor

vicentematus commented Mar 28, 2023

Here's what I've been trying: the hashchange event emits an special event called HashChangeEvent which contails newURL and oldURL properties. Whenever we detect a change in the hash, we compare if there has been a change (maybe this is redundant).

But whenever i try to update the store.page inside the svelte:hashchange acts kinda weird. Like there is some kinda race or something.

Lets say we update the page with the new hash on the hashchange event:

addEventListener('hashchange', (event) => {
    const new_url = new URL(event.newURL);
    const old_url = new URL(event.oldURL);
    // if the hashchange happened as a result of clicking on a link,
    // code here...

    // If the hash is the only thing that changed via user input, update the hash on the store
    if (new_url.hash != old_url.hash) {
	stores.page.set({ ...page, url: { ...page.url, hash: new_url.hash } });
	stores.page.notify();
	return;
    }

And this is the code for +page.svelte

<script>
	import { page } from '$app/stores';

	$: console.log('Store', $page.url.hash);
</script>

<svelte:window
	on:hashchange={() => {
	        console.log($page.url.hash, 'store');
		console.log(window.location.hash, 'location');
		
	}}
/>

If we replace #1 with #2 in the address bar, the expected output is 2. This is the scenario:

  1. ❗ The console.log of $page.url.hash will print: 1
  2. console.log of window.location.hash will print: 2
  3. ✅ the reactive $page.url.hash outside of the hashchange event will print the correct output: 2.

It's like hashchange event is not aware of the store changes? just after the first update of the store it will recognize it.

@GabrielBarbosaGV
Copy link

GabrielBarbosaGV commented Mar 28, 2023

Hello!

Would a change such as this be acceptable?

// This is within an else block for if (hash_navigating)

// In the occasion of the hash being updated directly through
// the browser's address bar, the page store needs to be
// updated
const url = new URL(location.href, document.baseURI);

current.url = url;

stores.page.set({ ...page, url });
stores.page.notify();

It seems to work with shallow, manual tests, but I am not sure about other implications. Furthermore, I've been unable to write a Playwright test to change the address bar and check the value's change in a div whose content is $page.url.

@moonmeister
Copy link

moonmeister commented May 23, 2023

exclamation The console.log of $page.url.hash will print: 1

I think this may be the same bug I have run into in #10013

UPDATE: Doesn't appear so

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working low hanging fruit ready to implement please submit PRs for these issues!
Projects
None yet
5 participants