0

I have nested draggable elements in my vue project and for drag event, I am using vue-draggable. So you can imagine my view something similar with this:

--> Element A
    --> Element B
        -->Element C
--> Element D
    --> Element E
-->Element F

I can freely drag one element into another. So I am trying to create a feature when I drag one element into another one, it should give a confirm warning with a modal. When Confirm is clicked, drag should stay how it is but if it is clicked to cancel, it should be reverted. And I am kindly expecting your help in this one. So for this I have ElementsListComponent:

<template>
    <div>
        <draggable
            v-model="newElement"
            v-bind="dragOptions"
            handle=".handle"
            :move="handleMove"
            @end="handleEnd"
        >
            <NestedElement
                v-for="(element, index) in newElement"
                :key="`${element.id}_${index}`"
                :element="element"
                @open-element-sidebar="openElementSidebar"
                @edit-entity="editEntity"
                @delete-entity="successfullDelete"
                :is-expanded="isExpanded"
            />
        </draggable>
        <Modal
            v-if="showWarningModal"
            @close="showWarningModal = false"
        >
            <template>
                Confirm Modal
            </template>
            <template #footer>
                <div class="buttons">
                    <button type="button" class="btn btn-primary mr-2" @click="showWarningModal = false">
                        {{ "Confirm" }}
                    </button>
                    <button type="button" class="btn btn-secondary" @click="revertDraggedElement">Cancel</button>
                </div>
            </template>
        </Modal>
    </div>
</template>

<script>
export default {
    props: {
        elements: {
            type: Array,
            required: true,
            default: () => [],
        },
        isExpanded: {
            type: Boolean,
            required: false,
            default: false,
        },
    },
    data() {
        return {
            newElement: [],
            dragOptions: {
                group: "plan-elements",
                animation: 150,
                ghostClass: "ghost",
                forceFallback: true,
                fallbackOnBody: true,
                chosenClass: "dragging",
                pull: "clone",
            },
            isLoading: false,
            showWarningModal: false,
            draggedElement: {},
            parentElement: {},
            draggedElementInitialState: {},
        };
    },
    methods: {
        openElementSidebar(sidebarName, element) {
            this.$emit("open-element-sidebar", sidebarName, element);
        },
        successfullDelete() {
            this.$emit("delete-entity");
        },
        editEntity(id, type) {
            this.$emit("edit-entity", id, type);
        },
        handleMove(event) {
            if (event.draggedContext.element) {
                this.draggedElement = event.draggedContext.element;
            }

            // Store the initial state of the dragged element
            this.draggedElementInitialState = {
                index: event.draggedContext.index,
                container: event.draggedContext.container,
                element: event.draggedContext.element,
            };

            if (event.relatedContext.element) {
                this.parentElement = event.relatedContext.element;
            }
        },
        handleEnd() {
            this.showWarningModal = true;
        },
        revertDraggedElement() {
            // I dont know what to do here
        },
    },
    watch: {
        elements: {
            handler(newVal) {
                this.newElement = newVal;
            },
            immediate: true,
        },
    },
};
</script>

and here is my NestedElement component:

<template>
    <div>
        <Element
            :element="element"
            @toggle-accordion="toggleAccordion"
            @open-element-sidebar="openElementSidebar"
            @delete-entity="successfullDelete"
            @edit-entity="editEntity"
            :has-child="hasChildElement"
            :is-expanded="isOpen"
        />
        <draggable
            v-if="element.childElements && element.childElements.data"
            v-model="element.childElements.data"
            v-bind="dragOptions"
            class="child-elements-container"
            handle=".handle"
            :move="handleMove"
            @end="handleEnd"
        >
            <NestedElement
                v-if="isOpen || (isOpen && isAllOpen)"
                v-for="(childElement, index) in element.childElements.data"
                :key="`${childElement.id}_${index}`"
                :element="childElement"
                @open-element-sidebar="openElementSidebar"
                @delete-entity="successfullDelete"
                @edit-entity="editEntity"
                :is-open="isOpen"
                :is-expanded="isAllOpen"
            />
        </draggable>
        <Modal
            v-if="showWarningModal"
            @close="showWarningModal = false"
        >
            <template>
                Confirm Modal
            </template>
            <template #footer>
                <div class="buttons">
                    <button type="button" class="btn btn-primary mr-2" @click="showWarningModal = false">
                        {{ "Confirm" }}
                    </button>
                    <button type="button" class="btn btn-secondary" @click="revertDraggedElement">Cancel</button>
                </div>
            </template>
        </Modal>
    </div>
</template>

<script>
export default {
    name: "NestedElement",
    props: {
        element: {
            required: true,
            type: Object,
        },
        isExpanded: {
            type: Boolean,
            required: false,
            default: false,
        },
    },
    data() {
        return {
            dragOptions: {
                group: "plan-elements",
                animation: 150,
                ghostClass: "ghost",
                forceFallback: true,
                fallbackOnBody: true,
                chosenClass: "dragging",
                pull: "clone",
                revertClone: true,
            },
            isAllOpen: false,
            isOpen: false,
            showWarningModal: false,
            draggedElement: {},
            parentElement: {},
        };
    },
    computed: {
        hasChildElement() {
            if (this.element.childElements) {
                return this.element.childElements.data.length ? true : false;
            }
        },
    },
    methods: {
        openElementSidebar(sidebarName, element) {
            this.$emit("open-element-sidebar", sidebarName, element);
        },
        successfullDelete() {
            this.$emit("delete-entity");
        },
        editEntity(id, type) {
            this.$emit("edit-entity", id, type);
        },
        toggleAccordion(isOpen) {
            this.isOpen = isOpen;
        },
        handleMove(event) {
            if (event.draggedContext.element) {
                this.draggedElement = event.draggedContext.element;
            }

            if (event.relatedContext.element) {
                this.parentElement = event.relatedContext.element;
            }
        },
        handleEnd() {
            this.showWarningModal = true;
        },
    },
    watch: {
        isExpanded: {
            handler(newVal) {
                this.isAllOpen = newVal;
                this.isOpen = newVal;
            },
            immediate: true,
        },
    },
};
</script>

I hope I am clear, I think storing initial state is correct but I dont know how to bring the draggable elements into their initial state if it is canceled. Thank you for the helps.

0