Vue.Draggable icon indicating copy to clipboard operation
Vue.Draggable copied to clipboard

How can i set a selected value without using the mouse (programmatically, on init) ?

Open edvinkuric opened this issue 3 years ago • 1 comments

Currently, i am trying to select an item of the draggable-list programmatically / manually (without the usage of the mouse).

This behaviour is important, because i want to make a pre-selection when the draggable-component is loaded. I wanted to use the "vuedraggable-multi" Fork (check #744 or https://github.com/divinespear/Vue.Draggable ) as well, which is based on this repository. This feature would allow me to select multiple elements for the drag-and-drop feature. I already tested the #744 and it works for me very well - sad to see that it is not merged yet.

I have read, that the "MultiDrag.singleton.utils.select()"-Method is the way to go for this, but my current Implementation does not contain this singleton (MultiDrag.singleton is undefined when i am importing MultiDrag). This link describes how it should have worked: https://www.fabiofranchino.com/log/add-programmatically-a-draggable-element-in-vuedraggable-with-sortable/

I can set the styling/css-class for the selected element manually, but this has no effect on the internal selection of the vueDraggable-component.

Jsfiddle link

N/A, since the feature does not exist yet afaik.

Relevant code-parts:

import { defineComponent, onMounted } from '@vue/composition-api';
import VueDraggable from 'vuedraggable';
import {Sortable, MultiDrag} from "sortablejs"; 

if (!MultiDrag.singleton) {
   console.log("singleton should exist, when using vuedraggable - but it doesn't");
   MultiDrag.singleton = new MultiDrag();
   Sortable.mount(MultiDrag.singleton);
}

export default defineComponent({
    name: 'MyPage',
    components: {
         draggable: VueDraggable
     },
    setup(_, ctx) {
  ... 
  onMounted(async () => { 
     // try to select a vuedraggable-item, when the items are loaded via API-call
      const el = ctx.refs.draggablelist.$el.querySelector(".selected");
     // the following line doesn't change the internal state of the draggable-list 
      MultiDrag.singleton.utils.select(el);
    }
  }
});

Step by step scenario

  1. Open up VueDraggable and try to set the list-selection via javascript.

Current Solution

N/A - no method currently available to select items programmatically. When importing MultiDrag from SortableJS ( import {Sortable, MultiDrag } from "sortablejs"; ), then the MultiDrag.singleton-field is undefined.

Expected Solution

  1. Expose the "MultiDrag.singleton.utils"-Methods from within VueDraggable, so that the selection can be done programmatically.
  2. If there are other methods for the item-selection, then expose these as well.
  3. Ideally, i can pass an Index/key of the listitem and the corresponding element is then added to the selection

Can you help me with this? That would be great :-) If you can point me to the solution, i also can do a PR if desired.

fyi @David-Desmaisons @divinespear

edvinkuric avatar Jun 05 '21 12:06 edvinkuric

I have found a work-around with sortable, my stack is::

{
    "vue": "^2.6.11",
    "vuetify": "^2.4.0",
    "sortablejs": "^1.14.0",
}

My test blade file is as shown below. See how I use Vue's $refs to trigger a selection to 2 items programmatically:

<template>
    <div class="fluid container">
        <v-btn @click="initDraggable" depressed dark>CLICK TO SELECT</v-btn>
        <v-row class="ma-7">
            <v-col cols="12">
                <div id="list" class="list-group">
                    <div class="list-group-item" ref="my-btn1">Item 1</div>
                    <div class="list-group-item" ref="my-btn2">Item 2</div>
                    <div class="list-group-item" ref="my-btn3">Item 3</div>
                    <div class="list-group-item" ref="my-btn4">Item 4</div>
                    <div class="list-group-item" ref="my-btn5">Item 5</div>
                    <div class="list-group-item" ref="button6">Item 6</div>
                    <div class="list-group-item" ref="button7">Item 7</div>
                </div>
            </v-col>
        </v-row>
    </div>
</template>

<script>
import { Sortable, MultiDrag } from 'sortablejs';

Sortable.mount(new MultiDrag());

export default {
    name: "hello",
    data() {
        return { };
    },
    methods: {
        initDraggable() {
            let list    = document.getElementById('list');

            Sortable.create(list, {
                group: 'shared',
                multiDrag: true,
                selectedClass: "selected",
                animation: 250
            });
           Sortable.utils.select(this.$refs.button6);
           Sortable.utils.select(this.$refs.button7);
        },
    },     
    mounted() {
        this.initDraggable();
        Sortable.utils.select(this.$refs.button6);
        Sortable.utils.select(this.$refs.button7);
    }
};
</script>

<style>
.selected {
    background-color: #f9c7c8 !important;
    border: solid red 1px !important;
    z-index: 1 !important;
}
.list-group {
    min-height: 20px;
}
.list-group-item {
    cursor: move;
}
.list-group-item i {
    cursor: pointer;
}
</style>

with this approach you can successfully have a single/multi-select capability done programmatically on button clock/or page load

ignatius-n avatar Mar 19 '22 14:03 ignatius-n