Skip to content

Instantly share code, notes, and snippets.

@IlCallo
Last active March 14, 2024 16:21
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save IlCallo/6abf4826a21662c7e8384a64c43aae53 to your computer and use it in GitHub Desktop.
Save IlCallo/6abf4826a21662c7e8384a64c43aae53 to your computer and use it in GitHub Desktop.
Apply Drag and Drop to QTable rows using SortableJs
// Taken from https://github.com/angular/components/blob/master/src/cdk/drag-drop/drag-utils.ts
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/** Clamps a number between zero and a maximum. */
function clamp(value: number, max: number): number {
return Math.max(0, Math.min(max, value));
}
/**
* Moves an item one index in an array to another.
* @param array Array in which to move the item.
* @param fromIndex Starting index of the item.
* @param toIndex Index to which the item should be moved.
*/
export function moveItemInArray<T = unknown>(
array: T[],
fromIndex: number,
toIndex: number
): void {
const from = clamp(fromIndex, array.length - 1);
const to = clamp(toIndex, array.length - 1);
if (from === to) {
return;
}
const target = array[from];
const delta = to < from ? -1 : 1;
for (let i = from; i !== to; i += delta) {
array[i] = array[i + delta];
}
array[to] = target;
}
<template>
<q-table :rows="rows" :columns="columns" row-key="name">
<template #body-cell-drag-handle="props">
<q-td :props="props">
<q-icon name="drag_handle" class="drag-handle" />
</q-td>
</template>
</q-table>
</template>
<script lang="ts">
import Sortable from 'sortablejs';
import {
defineComponent,
ref,
getCurrentInstance,
onMounted,
onUnmounted,
} from 'vue';
import { moveItemInArray } from './move';
const columns = [
{
name: 'drag-handle',
align: 'left',
},
{
name: 'name',
align: 'left',
label: 'Name',
field: 'name',
},
];
export default defineComponent({
name: 'QTableDndShowcase',
setup() {
const rows = ref([
{ name: 'Frozen Yogurt' },
{ name: 'Ice cream sandwich' },
{ name: 'Eclair' },
]);
let sortable: Sortable;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const instance = getCurrentInstance()!.proxy!;
onMounted(() => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const tableBody = (
instance.$el as HTMLElement
).querySelector<HTMLElement>('.q-table > tbody')!;
// Check out other options at https://github.com/SortableJS/Sortable#options
sortable = Sortable.create(tableBody, {
handle: '.drag-handle',
animation: 150,
onUpdate({ oldIndex, newIndex }) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
moveItemInArray(rows.value, oldIndex!, newIndex!);
},
});
});
onUnmounted(() => {
sortable.destroy();
});
return {
columns,
rows,
};
},
});
</script>
<style lang="scss" scoped>
.drag-handle {
cursor: move;
// stylelint-disable-next-line value-no-vendor-prefix
cursor: -webkit-grabbing;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment