Search code examples
javascriptvue.jsvuejs2frontenddraggable

Vue 2 draggable not reactive when v-model value is an iterable of parent tag


I am using Vue 2 with Vuex. The received object is first sorted into separate sub-objects based on classCategory value. Does it not work because the v-model value in draggable is a key from parent tag object?

<div class="class-draggable__group" v-for="group in groupedClasses" :key="group.categoryLocalised">
                    <label class="class-draggable__label__category">{{ group.categoryLocalised }}</label>
                    <draggable v-model="group.classes"
                        :options="{ group: 'classes', dragClass: 'drag', ghostClass: 'ghost' }">
                        <div v-for="classItem in group.classes" :key="classItem.class" class="class-draggable__draggable__item">
                            <div class="d-flex align-items-center">
                                <svg-icon name="drag" class="mr-8 move item"></svg-icon>
                                <div>{{ classItem.classLocalised }}</div>
                            </div>
                            <div class="class-info d-flex align-items-center">
                                <checkbox class="class-draggable__draggable__item__checkbox" :view="1"
                                    v-model="classItem.enabled" @select="toggleClassEnabledValue(classItem.class, $event)" />
                                <div class="icon-wrapper">
                                    <svg-icon v-if="classItem.boolVal1Enabled" name="boolVal1Icon"></svg-icon>
                                </div>
                                <div class="icon-wrapper">
                                    <svg-icon v-if="classItem.boolVal2Enabled" name="boolVal2Icon"></svg-icon>
                                </div>
                                <btn :content="{ icon: 'edit' }" class="class-draggable__draggable__item__button mr-8"
                                    round="circle" @click="editClassHandler(classItem.class)" />
                            </div>
                        </div>
                    </draggable>
                </div>
groupedClasses() {
            const groups = {};
            this.zoneInfoClasses.forEach(classItem => {
                if (!groups[classItem.categoryLocalised]) {
                    groups[classItem.categoryLocalised] = [];
                }
                groups[classItem.categoryLocalised].push(classItem);
            });
            return Object.keys(groups).map(categoryLocalised => ({
                categoryLocalised,
                classes: groups[categoryLocalised],
            }));
        },

here's the zoneInfoClasses object:

[
    {
        class: "classa"
        classLocalised: "classA"
        categoryLocalised: "category1"
        enabled: true
        boolVal1Enabled: false
        boolVal2Enabled: false
    }
    {
        class: "classb"
        classLocalised: "classB"
        categoryLocalised: "category2"
        enabled: false
        boolVal1Enabled: false
        boolVal2Enabled: false
    }
    {
        class: "classc"
        classLocalised: "classC"
        categoryLocalised: "category1"
        enabled: false
        boolVal1Enabled: false
        boolVal2Enabled: false
    }
    {
        class: "classd"
        classLocalised: "classD"
        categoryLocalised: "category2"
        enabled: false
        boolVal1Enabled: false
        boolVal2Enabled: false
    }
]

Dragging functionality is working fully visually only. When I release the dragged item all items are reset to their starting position.


Solution

  • I figured it out. Made it so that the new positioning is replaced instead of original positioning in groupedClasses and then ungroup groupedClasses back to how they were and commit to the value in store that is used to make groupedClasses itself.

    I added this to draggable opening tag: @change="handleDragEnd($event, group)"
    and this to methods:

    handleDragEnd(event, group) {
                this.groupedClasses.forEach(oldGroup => {
                    if (oldGroup.categoryLocalised === group.categoryLocalised){
                        oldGroup.classes = [...group.classes]
                    }
                });
    
                const ungroupedClasses = [];
                
                this.groupedClasses.forEach(group => {
                    group.classes.forEach(classItem => {
                        ungroupedClasses.push(classItem);
                    });
                });
                this.setZoneInfoValue({ prop: 'classes', value: ungroupedClasses });
            },
        ```