Search code examples
javascriptvue.jsvuejs2vue-componentdraggable

Draggable vue components


While replicating:

https://sortablejs.github.io/Vue.Draggable/#/nested-example

(code)

I ran into an issue related to the model; how can I add draggable to vue components instead of a raw json (as used in the example).

What I want to do is, add drag and drop to:

https://codesandbox.io/s/gg1en

(each item can be moved ("dragged") from one group to another, each group can be dragged from a lower position to an upper one (and vice-versa).

I tried:

https://codesandbox.io/s/quirky-sutherland-5s2zz?file=/src/components/InventorySectionC.vue

and got:

Unexpected mutation of "itemSectionData" prop. (vue/no-mutating-props)

but in this case the data comes from (through?) a prop.

The hierarchy of components is:

ChromePage --> InventorySectionC --> InventorySectionGroupC --> InventorySectionGroupItemC

I need components instead of plain JSON as each component has additional features (e.g. CRUD).

How should I go about combining components with draggable?


Solution

  • If you have a component prop that's being mutated, there are multiple options:

    1. Convert your prop to a custom v-model. It will allow two-ways bindings without problems. (Use the prop name value and sent $emit('input', this.value) to update it.
    2. Use prop.sync modifier, which is kinda the same as using v-model but the prop has a specific name. Use :data.sync="myItems" on the parent, and run $emit('update:data', this.data) inside the component to update it.
    3. Copy the prop to a data variable inside the component. So that the prop is only used as a default value for this data, but then it's only the data that's being mutated. But this won't allow the parent to see any modifications on that prop since it's not being updated directly.
    <template>
      <draggable v-model="_data"></draggable>
    </template>
    
    <script>
    props: {
      data: { type: Object, required: true }
    }
    data() {
      return {
        _data: {}
      }
    }
    mounted() {
      // Copy
      Object.assign(this._data, this.data)
    }
    </script>