Quantcast
Channel: Active questions tagged svelte - Stack Overflow
Viewing all articles
Browse latest Browse all 1541

Svelte 5 reactive $state in external module (dragListener)

$
0
0

I am trying to refactor a dragListener into a .svelte.js module by defining the position of the dragged element as a reactive $state() variable inside +page.svelte and pass it back and forth between the module and the +page.svelte.

The Svelte 5 Docs provide an example where let position = $state() is defined inside the external module (returning a getter function). But what shall I do, if I need to define let position = $state() inside +page.svelte?

Below I provide a minimal working example where the position of the element can be changed via a button and via drag. For both I provide handles in a helpers.svelte.js file. Inside +page.svelte I use $inspect(position) to check, whether state has updated. While inspect will fire on button click, it does not on drag.

I suppose, however, that the button-event only appears to be reactive because position is returned by handleClick(). While the lack of true reactivity is ok for a simple click action, it is an issue in the case of the drag listener.

So, how can I make position truly reactive?

Btw: I would be fine with using stores, too. However I don't get them working in external svelte.js files either. Also, according to the above linked Svelte 5 Docs, there should be a way to solve this with the $state() rune.

+page.svelte

<svelte:options runes="{true}" /><script>    import { onMount } from "svelte";    import {handleIncreaseX, handleDrag} from '$lib/helpers.svelte'    let item;    let position = $state({x:0, y:0});    $inspect(position); //??? why is it only reacting to the button but not to drag?    let onclick = () => {        position = handleIncreaseX(item, position)    }    onMount(() => {         position = handleDrag(item, position);    });</script><h1>Position: {position.x} / {position.y}</h1><button {onclick}>Increase X</button><div id="draggable" bind:this={item}>Drag Me</div><style>    #draggable {        background-color: black;        color: white;        width: 200px;    }</style>

helpers.svelte.js

import interact from 'interactjs';export function handleIncreaseX(item, position) {    position.x += 1;    item.style.webkitTransform =  item.style.transform = `translate(${position.x}px,${position.y}px)`;    item.setAttribute('data-x', position.x);    item.setAttribute('data-y', position.y);    return position;}export function handleDrag(item, position) {    console.log('DRAG INIT')    interact(item).draggable({        inertia: false,        autoScroll: false,        onstart: (ev) => {            console.log('ONSTART');        },        onmove: (ev) => {            let el = ev.target;            // store the dragged position inside data-x/data-y attributes            let x = (parseFloat(el.getAttribute('data-x')) || 0) + ev.dx;            let y = (parseFloat(el.getAttribute('data-y')) || 0) + ev.dy;            // translate the element and update position attributes            el.style.webkitTransform =  el.style.transform = `translate(${x}px,${y}px)`;            el.setAttribute('data-x', x);            el.setAttribute('data-y', y);            position = {x:x, y:y};            console.log('ONMOVE', position);        },        onend: (ev)=>{            console.log('ONEND');        }    });    return position;}

Note: Reactivity does work perfectly fine, as long as I define the drag listener inside the +page.svelte. However, this is not an option for me.

+page.svelte

<svelte:options runes="{true}" /><script>    import { onMount } from "svelte";    import interact from 'interactjs';    import {handleIncreaseX} from '$lib/helpers.svelte'    let item;    let position = $state({x:0, y:0});    $inspect(position);    let onclick = () => {        position = handleIncreaseX(item, position)    }    onMount(() => {         console.log('DRAG INIT')        interact(item).draggable({            inertia: false,            autoScroll: false,            onstart: (ev) => {                console.log('ONSTART');            },            onmove: (ev) => {                let el = ev.target;                // store the dragged position inside data-x/data-y attributes                let x = (parseFloat(el.getAttribute('data-x')) || 0) + ev.dx;                let y = (parseFloat(el.getAttribute('data-y')) || 0) + ev.dy;                // translate the element and update position attributes                el.style.webkitTransform =  el.style.transform = `translate(${x}px,${y}px)`;                el.setAttribute('data-x', x);                el.setAttribute('data-y', y);                position = {x:x, y:y};                console.log('ONMOVE', position);            },            onend: (ev)=>{                console.log('ONEND');            }        });    });</script><h1>Position: {position.x} / {position.y}</h1><button {onclick}>Increase X</button><div id="draggable" bind:this={item}>Drag Me</div><style>    #draggable {        background-color: black;        color: white;        width: 200px;    }</style>

Viewing all articles
Browse latest Browse all 1541

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>