Shopify / draggable

The JavaScript Drag & Drop library your grandparents warned you about.
https://shopify.github.io/draggable
MIT License
18k stars 1.09k forks source link

Swappable:swap cancel async #603

Open Buffele opened 8 months ago

Buffele commented 8 months ago

Is it possible to cancel or delay the swappable swap event?

I'd like to implement swapping, doing an ajax call, depending on the result, success -> continue with swapped, failure, revert the swapping or rather not let it continue. For now event.cancel(); only seems to work with a synchronous call.

function delay(t, val) {
    return new Promise(resolve => setTimeout(resolve, t, val));
}

const containers = document.querySelectorAll('#container');

if (containers.length === 0) {
    return false;
}

const swappable = new Draggable.Swappable(containers, {
    draggable: '.Block--isDraggable',
    mirror: {
        constrainDimensions: true,
    },
    plugins: [Draggable.Plugins.ResizeMirror],
});

swappable.on('swappable:swap', async (e) => {
    await delay(1000);  
    e.cancel(); // Does not work anymore
    console.log('Swap');
});
Developateam commented 6 months ago

To achieve asynchronous event handling with the swappable:swap event in the Draggable library, you need to handle the cancellation or continuation of the swap in a way that integrates with your asynchronous logic. The e.cancel() method only works synchronously, so you need to find a way to defer the decision to cancel the event until your asynchronous code completes.

Here's how you can approach this problem by using a combination of requestAnimationFrame and a custom flag to handle the swap after the asynchronous operation completes: function delay(t, val) { return new Promise(resolve => setTimeout(resolve, t, val)); }

const containers = document.querySelectorAll('#container');

if (containers.length === 0) { return false; }

const swappable = new Draggable.Swappable(containers, { draggable: '.Block--isDraggable', mirror: { constrainDimensions: true, }, plugins: [Draggable.Plugins.ResizeMirror], });

let shouldCancelSwap = false;

swappable.on('swappable:start', (e) => { shouldCancelSwap = false; });

swappable.on('swappable:swap', async (e) => { // Prevent the default swap action immediately e.cancel();

// Perform your asynchronous operation
const result = await delay(1000);

// Depending on the result, decide whether to cancel the swap or not
if (/* condition to allow swap, e.g., result is successful */) {
    shouldCancelSwap = false;
} else {
    shouldCancelSwap = true;
}

// Use requestAnimationFrame to wait for the next frame before continuing
requestAnimationFrame(() => {
    if (!shouldCancelSwap) {
        // Manually trigger the swap event if the condition is met
        swappable.trigger('swappable:swap', e);
    }
});

});

// Optional: Handle the end of the swappable event to revert if necessary swappable.on('swappable:end', (e) => { if (shouldCancel