I created tree structure using DataTable from prime vue (https://tailwind.primevue.org/datatable/)
<template>
<div class="card">
<DataTable :value="visibleRows" dataKey="data.id" class="elements-list">
<Column>
<template #body="slotProps">
<div
:style="{
paddingLeft: slotProps.data.level * 20 + 'px',
display: 'flex',
alignItems: 'center',
}"
class="expandable-row"
>
<span
v-if="hasChildren(slotProps.data)"
class="expander-icon"
@click="toggleRow(slotProps.data)"
>
<i
:class="[
'pi',
expandedRows[slotProps.data.data.id]
? 'pi-chevron-down'
: 'pi-chevron-right',
]"
></i>
</span>
<span v-else style="width: 1em"></span>
<Element
:element-id="slotProps.data.data.id"
/>
</div>
</template>
</Column>
</DataTable>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, defineProps } from "vue";
import Element from "./Element.vue";
import DataTable from "primevue/datatable";
import Column from "primevue/column";
const props = defineProps({
elements: {
type: Array as () => any[],
required: true,
default: () => [],
},
expanded: {
type: Boolean,
required: false,
default: false,
},
});
const expandedRows = ref({});
const hasChildren = (rowData) => {
return rowData.data.childElements && rowData.data.childElements.length > 0;
};
const toggleRow = (rowData) => {
const id = rowData.data.id;
if (expandedRows.value[id]) {
delete expandedRows.value[id];
} else {
expandedRows.value[id] = true;
}
};
const flattenTree = (elements, level = 0) => {
let result = [];
elements.forEach((element) => {
result.push({
data: element,
level: level,
});
const isExpanded = expandedRows.value[element.id];
if (isExpanded && element.childElements && element.childElements.length > 0) {
const children = flattenTree(element.childElements, level + 1);
result = result.concat(children);
}
});
return result;
};
const visibleRows = computed(() => {
return flattenTree(props.elements);
});
watch(
() => props.expanded,
() => {
if (props.expanded) {
expandAllNodes(props.elements);
} else {
expandedRows.value = {};
}
}
);
const expandAllNodes = (nodes) => {
nodes.forEach((node) => {
expandedRows.value[node.id] = true;
if (node.childElements && node.childElements.length > 0) {
expandAllNodes(node.childElements);
}
});
};
if (props.expanded) {
expandAllNodes(props.elements);
}
</script>
<style lang="scss">
.elements-list {
.p-datatable-tbody > tr > td {
border: none;
padding: 0;
}
.expandable-row {
padding: 16px;
border: 1px solid #dbdbdb;
border-radius: 8px;
margin-bottom: 0.5rem;
width: 100%;
}
.expander-icon {
cursor: pointer;
margin-right: 0.5rem;
}
}
</style>
It is not the result of my code but imagine I have a structure like this and I want to add drag and drop option into this component.
So each Element should be wrapped with draggable so that they can be drag and drop anywhere. I tried vuedraggable (https://github.com/SortableJS/Vue.Draggable?ref=madewithvuejs.com) for it but it didnt work at all.
Could you please help me?
