I have a div
that I want the page to scroll to when it is mounted. That div has an id which is determined in URL search params.
Not sure why, when I call document.getElementById(#${referProductId}
), the result is null. Is it because of the conditional rendering? (note: referProductId exist)
Inside the script tag
let layout: "grid" | "list" = "grid"
let referProductId = ""
page?.subscribe(({ url }) => {
// set layout value
// ... similar code to below with .get("layout")
const product_id = url.searchParams.get('product_id');
if (product_id) {
referProductId = product_id;
}
});
$: if (browser && referProductId) {
const product = document.getElementById(`#${referProductId}`);
console.log(product); // this logs null
if (product) {
product.scrollIntoView({ behavior: 'smooth' });
}
Inside the svelte markup
<div
class={cn(
'w-full gap-4',
displayType === 'grid' && 'grid grid-cols-2',
displayType === 'list' && 'flex flex-col'
)}
>
{#await data.products}
{#if displayType === 'grid'}
<Skeleton class="aspect-square h-full w-full rounded-lg" />
<Skeleton class="aspect-square h-full w-full rounded-lg" />
{:else if displayType === 'list'}
<div class="flex w-full flex-col gap-4">
<Skeleton class="h-16 w-full rounded-lg" />
<Skeleton class="h-16 w-full rounded-lg" />
</div>
{/if}
{:then products}
{#each products as product, i}
{#if displayType === 'grid'}
<div
id={String(product.id)}
in:fly={{
y: -40,
opacity: 0,
delay: i * 100,
duration: 250,
easing: cubicInOut
}}
>
<component />
</div>
{:else if displayType === 'list'}
<div
id={String(product.id)}
in:fly={{
y: -40,
opacity: 0,
delay: i * 100,
duration: 250,
easing: cubicInOut
}}
>
<component />
</div>
{/if}
{/each}
{:catch error}
<p>Error loading products</p>
{/await}
Would not recommend using manual subscriptions in component code, they are likely to cause leaks if not properly cleaned up. For focusing, you could approach it the other way around: From the element via an action.
$: referProductId = getProductId($page.url); // implement get logic in function
function scrollIntoView(node, scroll)
{
function update(scroll) {
if (scroll)
node.scrollIntoView({ behavior: 'smooth' });
}
update(scroll);
return { update };
}
<!-- on product element -->
<div
id={product.id}
use:scrollIntoView={product.id == referProductId}
...
You also could try hash-based navigation (just add/use #<id>
via goto
or links). For smooth scrolling via this mechanism, scroll-behavior: smooth
has to be set via CSS.