where on earth is vue-draggable item move to? - vue.js

I use nested draggable and listen events while drag, then find out that if i drag a itemA into itemB, event throws:
event add => newIndex, element.
event removed => oldIndex, element.
It tells me that itemA's index in itemB, but where on earth i konw who is itemB. something I missed? :3
I found it's hard to write a vue-draggable nested-component between 2 pages, i put a simple code to review it in your own computer(not really mine, copy official doc and little change ). code below
<template>
<div class="row">
<div class="col-8">
<h3>Nested draggable</h3>
<nested-draggable :tasks="list" />
</div>
</div>
</template>
<script>
import nestedDraggable from "./infra/nested";
export default {
name: "nested-example",
display: "Nested",
order: 15,
components: {
nestedDraggable
},
data() {
return {
list: [
{
name: "task 1",
tasks: [
{
name: "task 2",
tasks: []
}
]
},
{
name: "task 3",
tasks: [
{
name: "task 4",
tasks: []
}
]
},
{
name: "task 5",
tasks: []
}
]
};
}
};
</script>
<style scoped></style>
and infra/nested
<template>
<draggable class="dragArea" tag="ul" :list="tasks" :group="{ name: 'g1' }" #change="changed">
<li v-for="el in tasks" :key="el.name">
<p>{{ el.name }}</p>
<nested-draggable :tasks="el.tasks" />
</li>
</draggable>
</template>
<script>
import draggable from "#/vuedraggable";
export default {
props: {
tasks: {
required: true,
type: Array
}
},
components: {
draggable
},
name: "nested-draggable",
methods: {
changed (event) {
console.log(event)
}
}
};
</script>
<style scoped>
.dragArea {
min-height: 50px;
outline: 1px dashed;
}
</style>
So far, pass a el.list can calculate its index with save level element, though, drag in a empty list need to be prevented.

Related

Nesting in VueDraggable is not not working

here's my problem :
I'm using the VueDraggable library in order to drag and drop elements between a DragBoard.vue and a DropBoard.vue, and a specific type of element should allow to be nested when it is in the DropBoard.
I'm going to take this element as an example :
"Grouped Items"
To do that I've followed this example : https://github.com/SortableJS/vue.draggable.next/blob/master/example/components/nested-example.vue
And this is what I get when I drop "Grouped Items" into the DropBoard.vue :
IMG
As you can see, the DropBoard appears a second time inside Grouped items for whatever reason. I've supposed that the nested-draggable tag also loop what is out of the draggable tag and I've no idea how to resolve that...
📄 dragItems.JSON (used in DragBoard.vue) :
1st object is a common element
2nd object is a nestable element
[
{
"type": "Simple list",
"title": "Simple list",
"id": 1,
"properties": "this is an item property"
},
...
{
"type": "Grouped items",
"title": "Grouped items",
"id": 10,
"properties": "this is an item property",
"tasks": []
},
...
]
🚩 DropBoard.vue template:
<template>
<div class="board">
<div class="head">Mock</div>
<div class="dd-container">
<draggable
:list="tasks"
v-model="dropItems"
item-key="title"
:group="{ name: 'items', put: true }"
#change="log"
>
<template #item="{ element }">
<div
class="item"
:key="element"
>
<div>
{{ element.title }}
</div>
<nested-draggable
v-if="element.tasks"
:tasks="element.tasks"
class="group-container"
/>
<div class="trashico" :key="index">
<i class="fas fa-trash" #click="deleteItem(index)"></i>
</div>
</div>
</template>
</draggable>
</div>
</div>
</template>
🚩 DropBoard.vue script
<script>
import draggable from "vuedraggable";
export default {
name: "nested-draggable",
components: {
draggable,
},
props: {
dropItems: {
type: Array,
required: true,
},
tasks: {
required: true,
type: Array,
},
},
data() {
return {
dropItems: [],
};
},
methods: {
deleteItem(id) {
this.dropItems.splice(id, 1);
},
},
};
</script>
Here is what I found while using the Vue DevTools, it's quit explicit about the problem.
See image: IMG

get selected checkbox from child component

i'm showing up all category and subcategory with recursive component. i want to get all selected categor's id in parent component.
in my code when i select sub cat it does not return anything how can i fix this?
you can see live example here
https://codesandbox.io/s/eloquent-waterfall-3cpfe?file=/src/App.vue
parent component.
<template>
<div id="app">
<Child :cats.sync="selectedCategories" :categories="categories"/>
</div>
</template>
<script>
export default {
data: function() {
return {
categories: [
{ id: 1, name: "Category 1", children: [
{id: 11, name:"sub1", children: [
{id: 111, name: "sub 2", children: []}
]}
] },
{ id: 2, name: "Category 2", children: [] },
{ id: 3, name: "Category 3", children: [] }
],
selectedCategories: []
};
},
};
</script>
child component:
<template>
<div class="hello">
<label v-for="c in categories" :key="c.id">
<input v-model="temp" type="checkbox" :value="c">
{{ c.name }}
<template v-if="c.children.length > 0">
<Child :categories="c.children" />
</template>
</label>
</div>
</template>
<script>
export default {
name: "Child",
props: {
categories: Array,
cats: Array
},
computed: {
temp: {
get: function() {
return this.cats;
},
set: function(newValue) {
this.$emit("update:cats", newValue);
}
}
}
};
</script>
It does not work because you are binding subcategories with <HelloWorld v-model="temp" :categories="c.children" /> instead of <HelloWorld :cats.sync="temp" :categories="c.children" />

Draggable in Vue 3 won't display value

I am using Vue draggable to sort items from my Store.js by drag and drop (I've simplified my example here using only ['a', 'b', 'c'] as my store data).
I am also using a computed property made accessible from the setup()
<draggable v-model="myList" item-key="id" #start="drag=true" #end="drag=false" >
<template #item="{card}">
<p>{{ card }}</p>
</template>
</draggable>
import draggable from 'vuedraggable';
export default {
name: "Dashboard",
components: {
draggable
},
setup() {
const cards = computed(() => {
return ['a', 'b', 'c']
})
return {
cards
}
}
}
I know the template iterates through cards but no value is displayed or is neither accessible.
In Vue 3 - When setup is executed, the component instance has not been created yet. As a result, you will not have access to data, computed, methods component options.
Reference:
https://v3.vuejs.org/guide/composition-api-setup.html#accessing-component-properties
Also in Draggable component, the array item will be accessed by element variable.
Updated template code:
<draggable v-model="myList" item-key="id" #start="drag=true" #end="drag=false" >
<template #item="{element}">
<p>{{ element.value }}</p>
</template>
</draggable>
Try changing the component code as follows,
import draggable from 'vuedraggable';
export default {
name: "Dashboard",
components: {
draggable
},
data:function(){
return {
drag:false
}
},
computed:{
myList:function(){
return [{id:1,value:'Card A'},{id:2, value:'Card B'}];
}
}
}
yarn add vue-draggable-next
<draggable class="w-full mt-5 dragArea list-group" :list="list" #change="log">
<div
class="max-w-md p-2 mb-5 border cursor-pointer list-styles"
v-for="element in list"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
</template>
<script>
import { defineComponent } from "vue";
import { VueDraggableNext } from "vue-draggable-next";
export default defineComponent({
components: {
draggable: VueDraggableNext,
},
data() {
return {
enabled: true,
list: [
{ name: "Medical science", id: 1 },
{ name: "Allied Medicine", id: 2 },
{ name: "Defense Service", id: 3 },
{ name: "Education training", id: 4 },
{ name: "Economics & Commerce", id: 5 },
{ name: "Banking & Finance", id: 6 },
{ name: "Enginnering", id: 7 },
{ name: "science", id: 8 },
],
dragging: false,
};
},
methods: {
log(event) {
console.log(event);
},
},
});
</script>

Add or removing a class to a element in a child component

I've recently hit a wall with vue. Currently we three components Parent.vue ChildOne.vue and ChildTwo.vue. Parent Passes some object data (from a state) to the ChildOne component.
The ChildOnecomponent has the ChildTwo component as a custom element. On that custom element <ChildTwo></ChildTwo> we have a v-for loop that loops through the data and the ChildTwo component is just for html formatting the data.
What I want to is on a click add a custom class .selected to a div and remove it from the other div if selected, much like my example here.
https://codepen.io/david-wh/pen/gOrzQVR
Here is a sandbox of the full app I'm using:
https://codesandbox.io/s/onclick-forked-tkkre
Parent
<template>
<div>
<ChildOne :container-slot-data="ObjectData"></ChildOne>
</div>
</template>
<script>
import ChildOne from "./childComponentOne.vue";
export default {
name: "HelloWorld",
components: {
ChildOne
},
data() {
return {
ObjectData: [
{
id: "1",
name: "foo",
type: "aug",
subType: "1"
},
{
id: "2",
name: "bar",
type: "aug",
subType: "2"
},
{
id: "3",
name: "foobar",
type: "gear",
subType: "6"
}
]
};
}
};
</script>
ChildOne
<template>
<div class="Testing">
<ChildTwo v-for="(itemData, index) in containerSlotData" :key="index" :item-data="itemData"></ChildTwo>
</div>
</template>
<script>
import ChildTwo from "./childComponentTwo.vue";
export default {
name: "ChildOne",
components: {
ChildTwo
},
data() {
return {
current: null
};
},
props: {
containerSlotData: {
type: Array,
default: null
}
}
};
</script>
ChildTwo
<template>
<!-- <div class="selected"> -->
<div>
<ul>
<li>{{ itemData.id }}</li>
<li>{{ itemData.name }}</li>
<li>{{ itemData.subType }}</li>
</ul>
<hr>
</div>
</template>
<script>
export default {
name: "Childtwo",
data() {
return { current: null };
},
props: {
itemData: {
type: Object,
default: null
}
}
};
</script>
If all you want to do is to toggle the class on the elements, I suggest:
In ChildOne add a selectedItem to data and set it with #click handler.
In ChildTwo add a #click hanlder that will emit click event to the ChildOne compontent.
You can see a working example forked from your CodeSandbox here
I have added font-weight: bold to the .selected class to make it visible.

How to disable vue draggable placeholder

I am currently doing a website builder, where user can drag and drop to add element.
The drag and drop works well, but what i want is, how can i disable/hide the drop placeholder in the target container ?
As show in the image, whenever I hover on a container, it will show a copy of my dragging element by default, which I don't want.
Here is my code :
<template>
<div style="display : flex;">
<div id="dragArea">
<draggable
class="dragArea list-group"
:list="list1"
:group="{ name: 'item', pull: 'clone', put: false }"
:clone="cloneItem"
#change="log"
>
<div class="list-group-item" v-for="element in list1" :key="element.id">{{ element.name }}</div>
</draggable>
</div>
<div id="dropArea">
<draggable class="dragArea list-group" :list="list2" group="item" #change="log">
<div class="list-group-item" v-for="element in list2" :key="element.id">{{ element.name }}</div>
</draggable>
</div>
</div>
</template>
Script :
<script>
import draggable from "vuedraggable";
let idGlobal = 8;
export default {
name: "custom-clone",
display: "Custom Clone",
order: 3,
components: {
draggable,
},
data() {
return {
hover : false,
list1: [
{ name: "cloned 1", id: 1 },
{ name: "cloned 2", id: 2 },
],
list2: [
]
};
},
methods: {
log: function(evt) {
window.console.log(evt);
},
cloneItem({ name, id }) {
return {
id: idGlobal++,
name: name
};
},
},
};
</script>
On each of your <draggable> components within your <template>, you can set the ghost-class prop to a CSS class that hides the drop placeholder (ie. "ghost", or "dragging element" as you called it) using display: none; or visibility: hidden;.
For example:
In your <template>:
<draggable ghost-class="hidden-ghost">
and in the <style> section of your Vue Single File Component, or in the corresponding stylesheet:
.hidden-ghost {
display: none;
}
Working Fiddle
The ghost-class prop internally sets the SortableJS ghostClass option (see all the options here). The ability to modify these SortableJS options as Vue.Draggable props is available as of Vue.Draggable v2.19.1.