[SalesForce] dragable div element in LWC

below HTML and JS I have written by going through some documentation on drag event.
Not able to save anything on LWC playground so posted all code below which renders as shown in the below image.

enter image description here

added drag event on seq no column so that user can re order the data by just drag and drop seq number data.

HTML:

<template>
    <lightning-layout>
        <lightning-layout-item size="12" padding="horizontal-small">
            <lightning-card>
                <table>
                    <thead>
                        <tr>
                            <th scope="col">
                                Seq no.
                            </th>
                            <th scope="col">
                                Name
                            </th>
                            <th scope="col">
                                age
                            </th>
                            <th scope="col">
                                sex
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                        <template for:each={dataArray} for:item="data">
                            <tr key={data.seqNumber}>
                                <td>
                                    <div draggable="true" ondragstart={handleDragStart} 
                                    ondragend={handleDragEnd} data-item={data.seqNumber}>
                                        {data.seqNumber}
                                    </div>
                                </td>
                                <td>
                                    {data.name}
                                </td>
                                <td>
                                    {data.age}
                                </td>
                                <td>
                                    {data.sex}
                                </td>
                            </tr>
                        </template>
                    </tbody>
                </table>
            </lightning-card>
        </lightning-layout-item>
    </lightning-layout>
</template>

JS:

import { LightningElement, track } from 'lwc';

export default class App extends LightningElement {

    dataArray = [{
        seqNumber: 1,
        name: 'John',
        age: 50,
        sex: 'Male'

    },
    {
        seqNumber: 2,
        name: 'Moira',
        age: 51,
        sex: 'Female'
    },
    {
        seqNumber: 3,
        name: 'Sheldon',
        age: 52,
        sex: 'Male'
    },
    {
        seqNumber: 4,
        name: 'Nina',
        age: 42,
        sex: 'Female'
    },
    {
        seqNumber: 5,
        name: 'Morgan',
        age: 34,
        sex: 'Male'

    }]

    handleDragStart(event) {
        event.dataTransfer.dropEffect = 'move';

        let seqNumber = event.target.dataset.item;
        console.log('seqNumber ' + seqNumber);

    }

    handleDragEnd(event) {

        console.log(event);

    }
}

but the above one is not enough to make <td> dragable.
I can get the data id of the one which I am dragging but not getting anything on where I dropped handleDragEnd throws error.

can someone please point me to the right direction to make an HTML table content dragable?

Best Answer

I finally solved it by updating HTML and JS as below:

added ondrop, ondropover with preventdefaults as ondrop alone wont fire in HTML and then move array element in JS to show updated HTML

HTML:

    <template>
        <lightning-layout>
            <lightning-layout-item size="12" padding="horizontal-small">
                <lightning-card>
                    <table>
                        <thead>
                            <tr>
                                <th scope="col">
                                    Seq no.
                                </th>
                                <th scope="col">
                                    Name
                                </th>
                                <th scope="col">
                                    age
                                </th>
                                <th scope="col">
                                    sex
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            <template for:each={dataArray} for:item="data">
                                <tr key={data.seqNumber}>
                                    <td>
                                        <div draggable="true" ondragstart={handleDragStart} 
                                        ondrop={handleDrop} 
ondragover={handleDragover}
data-item={data.seqNumber}>
                                            {data.seqNumber}
                                        </div>
                                    </td>
                                    <td>
                                        {data.name}
                                    </td>
                                    <td>
                                        {data.age}
                                    </td>
                                    <td>
                                        {data.sex}
                                    </td>
                                </tr>
                            </template>
                        </tbody>
                    </table>
                </lightning-card>
            </lightning-layout-item>
        </lightning-layout>
    </template>

JS:

  import { LightningElement, track } from 'lwc';
    
    var indexFrom;
    var indexTo;
    
    export default class App extends LightningElement {
    
        @track dataArray = [{
            seqNumber: 1,
            name: 'John',
            age: 50,
            sex: 'Male'
    
        },
        {
            seqNumber: 2,
            name: 'Moira',
            age: 51,
            sex: 'Female'
        },
        {
            seqNumber: 3,
            name: 'Sheldon',
            age: 52,
            sex: 'Male'
        },
        {
            seqNumber: 4,
            name: 'Nina',
            age: 42,
            sex: 'Female'
        },
        {
            seqNumber: 5,
            name: 'Morgan',
            age: 34,
            sex: 'Male'
    
        }]
    
        handleDragStart(event) {
            event.dataTransfer.dropEffect = 'move';
    
            indexFrom = this.getIndex(parseInt(event.target.dataset.item, 10));
            
    
        }
    
        getIndex(index) {
            return this.dataArray.map(function(e) { return e.seqNumber; }).indexOf(index);
        }
    
    
        handleDrop(event) {
    
            indexTo = this.getIndex(parseInt(event.target.dataset.key, 10));
            
            let cutOut = this.dataArray.splice(indexFrom, 1) [0]; // cut the element at index 'from'
                this.dataArray.splice(indexTo, 0, cutOut);
          
            console.log(JSON.stringify(this.dataArray));
    
        }
    }

handleDragover(event) {
        event.preventDefault();
    }

If any one has any better solutions, please do post it.

Related Topic