Search code examples
vue.jsvuedraggable

How to work with arrays of arrays with vuedraggable


I have to face with problem in my vuejs experiments.

I have two arrays in my data, for example:

columns: [
    { name: "col1" },
    { name: "col2" },
    { name: "col3" },
    { name: "col4" }
  ],
  items: [
    {
      name: "col1-i1",
      id: 1241,
      column: "col1"
    },
    {
      name: "col1-i2",
      id: 1241242,
      column: "col1"
    },
    {
      name: "col2-i1",
      id: 1242421,
      column: "col2"
    }
  ]

Then I build object which consist of both this arrays so:

computed: {
list() {
  return this.columns.map(col => {
    return {
      column: col,
      items: this.items.filter(item => item.column === col.name)
    };
  });
}
},

After this in my list object I have this structure:

[{
"column": {
  "name": "col1"
},
"items": [
  {
    "name": "col1-i1",
    "id": 1241,
    "column": "col1"
  },
  {
    "name": "col1-i2",
    "id": 1241242,
    "column": "col1"
  }
]},{
"column": {
  "name": "col2"
},
"items": [
  {
    "name": "col2-i1",
    "id": 1242421,
    "column": "col2"
  }
]},{
"column": {
  "name": "col3"
},
"items": []},{
"column": {
  "name": "col4"
},
"items": []}]

I try to make draggable items in 4 columns, so:

<div class="column" v-for="(column, index) in list" :key="index">
  {{column.column.name}}
  <draggable group="a" :list="column.items">
    <div class="item" v-for="item in column.items" :key="item.id">{{item.name}}</div>
  </draggable>
</div>
</div>

but its not dragged into other column.

How to make it move right.

Example is here https://codesandbox.io/s/elated-aryabhata-uslwb?fontsize=14&hidenavigation=1&theme=dark


Solution

  • The issue is caused by the fact that the list object gets recomputed on change and you end up with the initial object, since the data used to generate it (columns and items) has not changed.

    Computed properties by default are getter only, and they only return the computed value. If you want to set the computed value, you will have to define a setter, and change the initial values of columns and items.

    But, for this use case, you should generate the list object in mounted hook, and then feed it to draggable component.

    data: () => ({
      list: [],
      columns: [...], // your columns
      items: [...] // your items
    })
    mounted(){
      this.list = this.columns.map(col => {
        return {
          column: col,
          items: this.items.filter(item => item.column === col.name)
        };
      });
    }
    

    If you plan to update columns and items dynamically, then you should define a watcher for these properties, and recompute the list.