Vue2からのマイグレーションで躓く
vue.draggableをドキュメントに記載があるとおりにマイグレーションしていくと、以下のようになる。
<!-- vue 2 version -->
<draggable v-model="myArray">
<div v-for="element in myArray" :key="element.id">{{element.id}}. {{element.name}}</div>
</draggable>
<!-- vue 3 version -->
<draggable v-model="myArray" item-key="id">
<template #item="{element}">
<div>{{element.id}}. {{element.name}}</div>
</template>
</draggable>
vue.draggableの中でvue.draggableを利用している場合はどうするんだろう?
例えば2階層のオブジェクト配列があり、それぞれを並び替えられるようにしたい場合、Vue2で以下のようになる。
// 2階層のオブジェクト配列
const myArray = [
{
id: 1,
name: "parent1",
childArray: [
{
id: 1,
name: "child1",
},
{
id: 2,
name: "child2",
}
]
},
{
id: 2,
name: "parent2",
childArray: [
{
id: 3,
name: "child3",
},
{
id: 4,
name: "child4",
}
]
},
]
<!-- vue 2 version -->
<draggable v-model="myArray">
<div v-for="element in myArray" :key="element.id">
<div>{{element.id}}. {{element.name}}</div>
<draggable v-model="element.childArray">
<div v-for="element2 in element.childArray" :key="element2.id">{{element2.name}}</div>
</draggable>
</div>
</draggable>
しかし、ここで問題になるのが、Vue3ではelementを別の名前にするとエラーになってしまうこと。
<!-- vue 3 version -->
<draggable v-model="myArray" item-key="id">
<template #item="{row}">
<div>{{row.id}}. {{row.name}}</div>
</template>
</draggable>
// TypeError: Cannot read properties of undefined (reading 'id')
ドキュメントだけを見るとここで詰んでしまい、子要素用のコンポーネントを別途作成することを考えなければならない気がするが、いちいち値を双方向に受け渡す必要が出てきてしまい、ちょっと面倒くさい。
っていうか、ループ変数が必ずelementになるってひどくない?
array
ならrow
とか、peoples
なら people
にして視認性を確保できないものか。
マニュアルに書いていないけど別名をつけることができた
<!-- vue 3 version -->
<draggable v-model="myArray" item-key="id">
<template #item="{element}">
<div>
<div>{{element.id}}. {{element.name}}</div>
<draggable v-model="element.myArray" item-key="id">
<template #item="{element: element2}">
<div>{{element2.id}}. {{element2.name}}</div>
</template>
</draggable>
</template>
</draggable>
{element: 別名}
とすることで今まで通り利用できるようになった。
これはindex
にも利用可能で、{element: row, index: idx1}
などといった設定が可能。
フォームだとID属性つけたり、引数付きcomputed
でゴニョゴニョするのにindex
を利用することも多いので、ここも任意の変数にできないと困るので非常に助かる。
<!-- vue 3 version -->
<!-- 視認性アップ -->
<draggable v-model="myArray" item-key="id">
<template #item="{element: parentRow, index: idx1}">
<div>
<div>{{ idx1 + 1 }}行目: {{parentRow.id}}. {{parentRow.name}}</div>
<draggable v-model="parentRow.myArray" item-key="id">
<template #item="{element: childRow, index: idx2}">
<div>{{ idx1 + 1 }}行目の{{ idx2 + 1 }}個目: {{childRow.id}}. {{childRow.name}}</div>
</template>
</draggable>
</template>
</draggable>
参考資料
この使い方は唯一、Issueにてこの方法を見つけることができた。
ちゃんとドキュメントに書いておいてほしい・・・vue.draggableのマイグレーションで躓いている人、多いと思うんだ・・・
https://github.com/SortableJS/vue.draggable.next/issues/165