Skip to content

Instantly share code, notes, and snippets.

@martinandersen3d
Last active December 8, 2017 00:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save martinandersen3d/3ae79ab03cd7a43b4dfe31cd56f2bf14 to your computer and use it in GitHub Desktop.
Save martinandersen3d/3ae79ab03cd7a43b4dfe31cd56f2bf14 to your computer and use it in GitHub Desktop.
vue draggable nested tree [Solution & Working, vue 2.x]
// PARENT -----------------------------------------------------
<template>
<div>
<devinfo :code='$data' name='treeParent' ></devinfo>
<b-field label="Add Page">
<input ref='pageTextField' @keyup.enter="addPageFromTextfield" v-model="textfieldvalue">
</b-field>
<treeChild :data="data"></treeChild>
</div>
</template>
<script>
export default {
methods:{
addPageFromTextfield () {
// var node = new TreeNode(this.textfieldvalue, false, Math.floor(Math.random() * (99999999 - 11111111) ) + 11111111)
// if (!this.data.children) this.data.children = []
// node['funky']="asda"
// console.log(node);
// this.data.addChildren(node)
// this.textfieldvalue =""
this.addPage(this.textfieldvalue)
this.$refs.pageTextField.select()
},
addPage(newPageName){
this.data.push({
name: newPageName,
show:true,
type:'page',
children: []
})
}// addPage
},
data() {
return {
textfieldvalue:"",
data: [
{
name: "FolderA",
show:true,
freeze:true,
type:'page',
children: [{
name: "Alpha-Folder",
show:false,
freeze:true,
children: [{
name: "Sub-Alpha1"
},
{
name: "Sub-Alpha2"
},
{
name: "Sub-Alpha3",
freeze:true
},
{
name: "Sub-Alpha4"
},
{
name: "Sub-Alpha5"
}
]
},
{
name: "Alpha2"
},
{
name: "Alpha3"
},
{
name: "Alpha4"
},
{
name: "Alpha5"
}
]
},
{
name: "FolderB",
show:true,
type:'page',
children: [{
name: "Bravo1"
},
{
name: "Bravo2"
},
{
name: "Bravo3"
},
{
name: "Bravo4"
},
{
name: "Bravo5"
}
]
},
{
name: "FolderC",
type:'page',
freeze:true,
show:false,
children:[]
},
{
name: "FolderD",
type:'page',
show:false,
children:[]
}
]
}
}, //data
}
</script>
// CHILD -----------------------------------------------------
<template>
<draggable :list="data" :options="folderOptions" id="treeWrapper" @start="dragStart" @end="dragEnd" :move="checkMove">
<template v-for="(node, index) in data" >
<ul v-if="node.children" class="node" id="asdasdasd">
<div class=" treeItem ">
<span v-if="node.type == 'page'" @click="node.show =! node.show"><ico :i=" iconFolder( node.show ) " o='' :styleDiv=" 'display: inline-block' "></ico> </span>
<span v-else @click="node.show =! node.show"><ico :i=" iconPlus( node.show ) " o='' :styleDiv=" 'display: inline-block' "></ico> </span>
<span @dblclick="renameItem(node)" @click="setActivePage(_uid +'-' + index)" :class=" { treeItemFrozen : node.freeze}">{{ node.name }}</span>
</div>
<traverser v-if="node.show" :data="node.children" :options="nodeOptions" ></traverser>
<!-- Empy items while dragging -->
<traverser v-if="node.children && node.children.length == 0" id="innerTreeWrapper" :data="node.children" :options="nodeOptions" :class=" [ 'dragAreaInActive', {dragAreaActive : isDragging } ] "></traverser>
</ul>
<li v-else class="leaf treeItem" @mouseover="setActivePage(_uid +'-' + index)" @mouseout="fakeMouseOverId=''">
<span v-if="node.type == 'page'" @click="node.show =! node.show" ><ico :i=" iconFolder( node.show ) " o='' :styleDiv=" 'display: inline-block' "></ico> {{ node.name }} </span>
<span else @dblclick="renameItem(node)" @click="setActivePage(_uid +'-' + index)" :class=" { treeItemFrozen : node.freeze}">{{ node.name }}</span>
<span v-if="fakeMouseOverId == _uid +'-' + index">
<span @click="deleteItem(data, index)" class='iconRight'><ico i=" fa-trash-o " o='' :styleDiv=" 'display: inline-block' " ></ico></span>
<span @click="renameItem(node)" class='iconRight'><ico i=" fa-pencil-square-o " o='' :styleDiv=" 'display: inline-block' " ></ico></span>
</span>
<traverser v-if="node.children && node.children.length == 0" id="innerTreeWrapper" :data="node.children" :options="nodeOptions" :class=" [ 'dragAreaInActive', { dragAreaActive : isDragging } ] "></traverser>
</li>
</template>
</draggable>
</template>
<script>
import draggable from 'vuedraggable';
export default {
name: 'traverser',
data () {
return {
folderOptions:{group:'folders', animation:100},
nodeOptions:{group:'people', animation:100},
isDragging: false,
isActivePage:'',
fakeMouseOverId:'' // index+_uid temporary id
};
},
props: {
data: {},
options: {},
},//data
methods:{
setActivePage(e){
this.fakeMouseOverId = e
},
checkMove(evt){
var itemMoved = evt.draggedContext.element.name // String | Returnere navnet på den component jeg trækker. Det navn den returnere her er navnet//!=='apple'
var fromIndex = evt.draggedContext.index // Int | from-index på componenten, hvor den bliver trukket fra.
var toIndex = evt.draggedContext.futureIndex // int | target-index på der component der bliver trukket til.
var idOfTarget = evt.to.id // int | target-id på der component der bliver trukket til.
var targetHtml = evt.to // int | target id navneet på target html objektet.
var relatedContext = evt.relatedContext // int | target id navneet på target html objektet.
// console.log('---------------------------------------------');
// console.log('checkMove:', itemMoved)
// console.log('checkMove - fromIndex:', fromIndex)
// console.log('checkMove - toIndex:', toIndex)
// console.log('checkMove - idOfTarget:', idOfTarget)
// console.log('checkMove - targetHtml:', targetHtml)
// console.log('checkMove - relatedContext:', relatedContext)
// console.log('evt:', evt)
// console.log('path:', evt.path)
var arr = evt.to;
function parentHasClass(val) {
var result = val.hasAttribute('class') && val.className == "node";
return result;
}
// var res = arr.find(parentHasClass); // 130
// console.log(res);
return (evt.draggedContext.element.freeze!==true);
},
renameItem(node){
var person = prompt("Rename - Please choose a new name:", node.name);
if (person != null) {
node.name = person
}
}, //renameItem end
deleteItem(data, index){
var theName = data[index].name
var r = confirm("Are you shure you want to delete this item: \n \n" + theName);
if (r == true) {
data.splice(index,1)
}
}, //deleteItem end
iconFolder(val){
if (val === true){ return 'folder-open' } else { return 'folder' }
}, //iconPlus end
iconPlus(val){
if (val === true){ return 'minus-square-o' } else { return 'plus-square-o' }
}, //iconPlus end
dragStart() {
this.isDragging = true
},
dragEnd(evt) {
this.isDragging = false
console.log('end:', evt.path);
},
}
} // export
</script>
<style scoped>
.leaf{
padding-left:22px;
list-style-type: none;
font-size:14px;
}
.node{
padding-left:20px;
font-size:16px;
}
.treeItem{
cursor: pointer;
}
.treeItem:hover{
color: #2196f3;
background-color: rgba(0,0,0,0.05)
}
.treeItemFrozen{
color: darkgray;
}
.iconContainer{
display: inline-block !important;
}
.dragAreaActive {
min-height: 15px !important;
display: block;
background:green !important;
}
.dragAreaInActive {
min-height: 10px;
display: block;
background:red;
}
.iconRight{
float: right;
margin-right: 10px;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment