Drag and Drop between LWC (Multiple)

In the previous post, we implemented Drag and Drop functionality in the same Lightning Web Component. You can check the full implementation here. In this post, we will implement the Drag and Drop between Multiple LWC (Lightning Web Component). This post will cover multiple implementations, so let’s grab a cup of coffee, and hop into the implementation.

Prerequisite

Before starting with the implementation, there are two topics that you need to understand: Lightning Message Service and HTML Drag and Drop API.

Lightning Message Service (LMS) is an extraordinary feature introduced recently that enables the communication between Visualforce Page, Aura Component, and Lightning Web Component anywhere on the Lightning Page. HTML Drag and Drop API provides standard methods to implement drag and drop in Lightning Web Component.

Good thing is that we have implemented both these topics in detail which you can check below:

Since we are implementing drag and drop between multiple components, we cannot move the DOM element directly from one component to another. So we will use HTML Drag and Drop API to capture the drag and drop events. Then we will use Lightning Message Service to communicate between both the Lightning Web Components.

Implementation

In this implementation, we will implement Drag and Drop between two LWC (Lightning Web Component). The First component will display the list of Upcoming Posts and the Second component will display the list of Completed Posts. After completing the implementation, we will be able to drag a post from Upcoming Posts and drop it into the Completed Posts component.

Follow the below steps to implement the Drag and Drop between Multiple LWC functionality.

  1. Create Lightning Message Service DragDrop__c.
  2. Create Lightning Web Component upcomingPosts. Use separate div tags to display the list of Posts.
  3. Use events of Drag and Drop API to capture the drag event, and publish a message using Lightning Message Service to send Content of Post, Id of the Div of Post, and boolean variable upcomingToCompleted.
  4. Create separate Lightning Web Component completedPosts to display a list of completed posts. Create a separate component post to display the individual post in completedPosts component. We have created this post component only for completedPosts as we have to create post dynamically after dropping. Because createElement() Javascript method does not work in Lightning Web Component.
  5. In completedPosts, use lstPosts to show default posts. In Constructor, subscribe to the Lightning Message Service that will add the content of the dragged post in draggedItem and Id of the post in draggedItemId.
  6. Add the method to capture the drop event. And the draggedItem in lstPosts to render it on UI. It will be displayed as soon as the lstPosts is updated as lstPosts is a Reactive property.

This is enough to drag and drop an element from one component to another. But dragged component should also be deleted from the first component. For this, follow below steps:

  1. In completedPosts, publish a message using Lightning Message Service to pass the Id of the dragged element that we stored in draggedItemId.
  2. In Constructor of upcomingPosts, subscribe to the Lightning Message Service that will get the Id of dragged element and hide/remove it from the UI. For this implementation, I am just hiding it from UI using CSS, you can remove it from UI or Database as per the requirement.
  3. Since we are using the same Message Channel to publish and subscribe from both the components, we are using the boolean parameter upcomingToCompleted to differentiate between subscribers. Based on its value, either one of the subscribe() code will execute.

That is all. These are the steps that we need to follow to implement Drag and Drop between Multiple LWC. I didn’t explain how HTML Drag and Drop API or Lightning Message Service works in this implementation. You can check the attached posts to check their implementations.

Drag and Drop between Multiple LWC

Implementation for Drag and Drop between LWC looks much like earlier but in this case, we are doing it between different components.

Drag and Drop between Multiple LWC
Drag and Drop between Multiple LWC

Before checking the code, if you like this implementation, please Subscribe here so that you can get notified every time a new implementation is published.

Code for Drag and Drop between LWC

upcomingPosts.html

<template>
    <lightning-card title="TO-DO POSTS LWC">
        <lightning-layout>
            <div class="slds-p-around_small">
                <div class="flex-container">
                    <div id="ToDo2" class="box" draggable="true" ondragstart={drag}>
                        Drag and Drop in Lightning Web Component (LWC)
                    </div>

                    <div id="ToDo3" class="box" draggable="true" ondragstart={drag}>
                        Drag and Drop between Multiple Lightning Web Components
                    </div>

                    <div id="ToDo4" class="box" draggable="true" ondragstart={drag}>
                        Like and Share if you like this Implementation.
                    </div>
                </div>
            </div>
        </lightning-layout>
    </lightning-card>
</template>

upcomingPosts.js

import { LightningElement } from 'lwc';
import { createMessageContext, releaseMessageContext, publish, subscribe } from 'lightning/messageService';
import DragDropChannel from "@salesforce/messageChannel/DragDrop__c";

export default class UpcomingPosts extends LightningElement {
    context = createMessageContext();
    subscription = null;

    constructor() {
        super();
        if (this.subscription) {
            return;
        }
        this.subscription = subscribe(this.context, DragDropChannel, (message) => {
            if(!message.upcomingToCompleted){
                this.template.querySelector('#' +message.itemId).style.display = 'none';
            }
        });
    }

    drag(event){
        const message = {
            draggedItem : event.target.textContent,
            itemId : event.target.id,
            upcomingToCompleted: true
        };
        publish(this.context, DragDropChannel, message);
    }

    disconnectedCallback() {
        releaseMessageContext(this.context);
    }
}

upcomingPosts.css

.box{
    border-radius: 10px;
    background-color: #faf59b;
    padding: 15px;
    width: 148px;
    height: 148px;
    display: inline-block;
    margin: 3px;
    font-size: 15px;
    text-align: center; 
}

.completed{
    background-color: #aafac3;
}

.flex-container {
    display: flex;
    flex-flow: row wrap;
    width: 463px;
}

completedPosts.html

<template>
    <lightning-card title="COMPLETED POSTS LWC">
        <lightning-layout>
            <div class="slds-p-around_small">
                <div id="idCompletedPosts" class="flex-container" ondragover={allowDrop} ondrop={drop}>
                    <template for:each={lstPosts} for:item="post">
                        <p key={post}>
                            <c-post title={post}></c-post>
                        </p>
                    </template>
                </div>
            </div>
        </lightning-layout>
    </lightning-card>
</template>

completedPosts.js

import { LightningElement, track } from 'lwc';
import { createMessageContext, releaseMessageContext, publish, subscribe, unsubscribe } from 'lightning/messageService';
import DragDropChannel from "@salesforce/messageChannel/DragDrop__c";

export default class CompletedPosts extends LightningElement {
    draggedItem;
    draggedItemId;
    context = createMessageContext();
    subscription = null;
    @track lstPosts = [];

    constructor() {
        super();
        this.lstPosts.push('Create Dynamic Apex Instance using Type.forName()');

        if (this.subscription) {
            return;
        }
        this.subscription = subscribe(this.context, DragDropChannel, (message) => {
            if(message.upcomingToCompleted){
                this.handleMessage(message);
            }
        });
     }

    handleMessage(message) {
        this.draggedItem = message.draggedItem;
        this.draggedItemId = message.itemId;
    }

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

    drop(event){
        event.preventDefault();
        this.lstPosts.push(this.draggedItem);
        const message = {
            draggedItem : null,
            itemId : this.draggedItemId,
            upcomingToCompleted: false
        };
        publish(this.context, DragDropChannel, message);
    }

    disconnectedCallback() {
        releaseMessageContext(this.context);
    }
}

completedPosts.css

.flex-container {
    display: flex;
    flex-flow: row wrap;
    width: 463px;
    height: 154.5px;
}

post.html

<template>
    <div class="box">
        {title}
    </div>
</template>

post.js

import { LightningElement, api } from 'lwc';

export default class Post extends LightningElement {
    @api title;
}

post.css

.box{
    border-radius: 10px;
    background-color: #aafac3;
    padding: 15px;
    width: 148px;
    height: 148px;
    display: inline-block;
    margin: 3px;
    font-size: 15px;
    text-align: center;
}

This is how we can implement Drag and Drop between LWC (Lightning Web Component) using HTML Drag and Drop API and Lightning Message Service.

If you want to check more implementation using Lightning Web Components, you can check it here.

Subscribe here if you don’t want to miss new implementations.

Check official documentation here if you want to know more about HTML Drag and Drop API.

See you in the next implementation.

4 thoughts on “Drag and Drop between LWC (Multiple)”

  1. Wow! This could be one particular of the most helpful blogs We’ve
    ever arrive across on this subject. Actually Wonderful.
    I’m also a specialist in this topic therefore I can understand your effort.

  2. Hi Nikhil,

    could you please help me ,how we can make this conferrable,like user adds the task from UI ?

    1. Hi Mohit, we are displaying lstPosts dynamically in completedPost component. You can maintain the same kind of list and display it on upcomingPosts component dynamically. Maintain a list of upcoming tasks/posts and add the new post in the list of upcoming posts when you want to add a new task/post. As soon as the new task is added to the list, it will render on UI dynamically.

Comments are closed.