Code Monkey home page Code Monkey logo

sortablejs-vue3's Introduction

SortableJS-vue3

Demo | npm

GIF of the demo being used

This is a thin wrapper around the great SortableJS library. I had many issues migrating from Vue.Draggable to vue.draggable.next, and after briefly investigating I decided that it was too complicated and a smaller solution was the answer. This wrapper attempts to keep you as close to Sortable as possible.

Why not use <other library>?

  • Vue.Draggable only supports Vue 2
  • vue.draggable.next uses the Options API, has multiple open (and afaict useful) pull requests, and had weird bugs/side-effects when I tried and used it
  • shopify/draggable and vue-shopify-dragable seemed promising but they don't supported nested components

Usage

You can see a demo with more complete code at https://sortablejs-vue3.maxleiter.com.

  1. Install the package:
pnpm add sortablejs-vue3 sortablejs

or

npm install sortablejs-vue3 sortablejs
  1. Import the component in your <script setup> (or <script>):
import { Sortable } from "sortablejs-vue3";
  1. Use the component:
<template>
  <main>
    <Sortable
      :list="elements"
      item-key="id"
      tag="div"
      :options="options"
    >
      <-- The Header and Footer templates below are optional -->
      <template #header>
          <header>
            <h1>SortableJS Vue3 Demo</h1>
          </header>
      </template>
      <template #item="{element, index}">
        <div class="draggable" :key="element.id">
          {{ element.name }}
        </div>
      </template>
      <template #footer>
          <footer class="draggable">A footer</footer>
      </template>
    </Sortable>
</template>
  1. The list and item-key props are necessary. The options prop is an object that can contain any SortableJS option. You can find a full list of them here: https://github.com/SortableJS/Sortable#options
    • The tag prop is optional and defaults to div. It's the HTML node type for the outer element of the included template/slot.

Props

  • list (Array<any>, required): your data to list
  • itemKey (string | (item) => (string | number | Symbol), required): The name of the key present in each item in the list that corresponds to a unique value (to use as the key)
  • tag (string, optional, default = "div"): The element type to render as
  • options (Object, false): the SortableJS options minus event handlers (see below)

Events

You can listen to Sortable events by adding the listeners to the Sortable component. For example:

<Sortable
  :list="elements"
  item-key="id"
  @change="(event: Sortable.SortableEvent) => void"
  @choose="(event: Sortable.SortableEvent) => void"
  @unchoose="(event: Sortable.SortableEvent) => void"
  @start="(event: Sortable.SortableEvent) => void"
  @end="(event: Sortable.SortableEvent) => void"
  @add="(event: Sortable.SortableEvent) => void"
  @update="(event: Sortable.SortableEvent) => void"
  @sort="(event: Sortable.SortableEvent) => void"
  @remove="(event: Sortable.SortableEvent) => void"
  @filter="(event: Sortable.SortableEvent) => void"
  @move="(event: Sortable.MoveEvent, event2: Event) => void"
  @move.capture="(event: Sortable.MoveEvent, event2: Event) => boolean | -1 | 1"
  @clone="(event: Sortable.SortableEvent) => void"
>

Using plugins

You need to mount any plugins you want outside of the default before importing this library. For example, the below is correct:

import SortableJs from "sortablejs";
import { Swap } from "sortablejs/modular/sortable.core.esm";
SortableJs.mount(new Swap());

import { Sortable } from "sortablejs-vue3";

Use with a store

No changes are necessary to work with Vuex or another store. Just pass store.state.items as your list. To modify your data you need to manually listen to the events and calculate the new position with event.oldIndex and event.newIndex with something like the following:

const moveItemInArray = <T>(array: T[], from: number, to: number) => {
  const item = array.splice(from, 1)[0];
  nextTick(() => array.splice(to, 0, item));
};

onEnd(event) { moveItemInArray(store.state.items, event.oldIndex, event.newIndex) }

You may also want to see the SortableJS store documentation here.

Examples

Development

  1. Run pnpm to install dependencies
  2. pnpm dev will start a web server with live reloading
  3. pnpm build will build the production library files
  4. pnpm build:site will build the demo website

Recommended IDE Setup

sortablejs-vue3's People

Contributors

bazmaster avatar billyct avatar eliottvincent avatar hjbdev avatar jwmoreland avatar kmohrf avatar maxleiter avatar messenjer avatar nlhkabu avatar p-rivero avatar palagadec avatar renovate[bot] avatar yahordanchanka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sortablejs-vue3's Issues

Build : error TS7056: The inferred type of this node exceeds the maximum length

Hello

Hi, I get this error when I try to build the library, do you get it too?

pnpm run build

> [email protected] build sortablejs-vue3
> vite build && vue-tsc --emitDeclarationOnly --project tsconfig.dist.json && mv dist/lib dist/types && rm -rf dist/favicon.ico

vite v4.0.4 building for production...
✓ 4 modules transformed.
dist/sortablejs-vue3.es.js  3.53 kB │ gzip: 1.16 kB
dist/sortablejs-vue3.umd.js  2.00 kB │ gzip: 0.99 kB
src/components/Sortable.vue:6:1 - error TS7056: The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.

  6 type SortableOptionsProp = Omit<
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  7   SortableOptions | AutoScrollOptions,
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
134 });
    ~~~
135 </script>

Found 1 error in src/components/Sortable.vue:6

Regards

Mathieu

Make SortableJS-vue3 compatible with vue2 ?

I know it sounds like a weird proposal.

At the end of the year, vue2 will reach end of life and that will imply that a lot of big legacy projects will have to migrate to vue3.

The migration is not so trivial, you have to migrate:

  • vue2 to vue3
  • core libraries: vue-router, vuex, ..
  • big ui libraries like vuetify, vue-bootstrap, ...
  • libraries like Vue.Draggable where there is no vue3 compatible version released as explained in the SortableJS-vue3 description

One approach is to be prepared to already migrate the legacy code base of the applications to vue2/vue3 compatible plugins, libraries

If SortableJS-vue3 becomes compatible with Vue2 using vue-demi, we could start migrating Vue.Draggable in vue2 legacy code to SortableJS-vue3 and then make it easier to migrate to vue3.

What do you think?

Mathieu

Accessing template refs for recursive sortable

I am using this library to build a nested list, using a recursive component.

You can see a demo of this here: https://stackblitz.com/edit/recursive-template-refs-b2umvk?file=src/components/EntryListItem.vue

Each entryListItem has a focusText method that I want to be able to call from anywhere by providing the entry ID

(one use case is that the user presses the up or down arrows on their keyboard and the focus is moved to the next item, regardless of indentation)

To do this I think I need to build a list of template refs, but I am struggling to do this because of the recursion. Any ideas on how I should move forward on this? Is this something that could/should be handled at this library's level?

Thanks in advance!

v-model support

It's nice someone have taken up the torch to keep the sortablejs library available and updated for vue3, but is there no way you could introduce v-model binding?

The amount of boilerplate you have to write when you need your component in more than 1 spot is absolutely insane.

I could write my own component that wraps yours, to handle things such as sorting/add/remove and other v-model related events, but it kinda defeats the purpose of having something "out of the box"

Hope you'll consider

Header and footer without the tags?

I like that you can add a header and footer, however I would like it without the

and tag. In our case we have an upload button at the end, but since the layout is in a css grid, the footer tag messes with the layout. Would it be possible to just have the slot and no html, and the app could inject the footer tag if necessary? Otherwise, if that's a breaking change, maybe add a slot for 'prepend' and 'append'?

'group' attribute not working

I'm trying to share components between two lists, but using the group attribute (with the same string) does not appear to be working.

I've checked the library itself and I also can't find references to this attribute.

Is it possible to share items between two lists with sortablejs-vue3?

Can't import in Vue script

I can't import { Sortable } from "sortablejs-vue3"; in my Composition api script :

GET http://localhost:5173/node_modules/.vite/deps/sortablejs-vue3.js?t=1673724793576&v=19972475 504 (Gateway Timeout)

tried putting my script in Ts did not help either, the import statement alone makes my app crash...

mulit drag support

Hope to increase mulit drag support.This is often used in many scenarios. because sortable haved mulitdrag plugin.

npm script

image

question:
i dont understand the command , beacuse i delete ,it also can compile ok , anyone can explain ?

Manage state when moving items between two lists

Thanks again for this lib.

I have multiple lists on my page and I want to be able to change some properties of my project. As with vue.draggable.next clone, I have provided the same grouping options for each list.

Now the question is:

  1. The 'taskList' has not been updated. The page already has the project, and the properties haven't changed

The sample code:

<template>
         <Sortable class="draggable" :list="elements" item-key="id" tag="div" :options="options" @clone="onClone">
            <template #item="{ element, index }">
                <div class="draggable" :key="element.id">
                    {{ element.name }}
                </div>
            </template>
        </Sortable>

         <Sortable class="draggable" :list="taskList" item-key="id" tag="div" :options="options">
            <template #item="{ element, index }">
                <div class="draggable" :key="element.id">
                    {{ element.name }}
                </div>
            </template>
        </Sortable>

</template>

<script setup>
const options = ref({
    group: "name",
})
const elements = ref([{ id: uuidv4(), name: "test1" }])
const taskList = ref([])
const onClone = function (evt) {
    let { oldIndex, } = evt;

    const obj = elements[oldIndex];
    let tempObj = {
        ...obj,
        id: uuidv4()
    }
    taskList.value.push(tempObj)
}

</script>

Using options API

Hey there,

I'm trying to use the library as recommended by just adding the main js file my project instead of installing it as a dependency. The rest of my codebase I'm using the options API though and I'm having trouble getting this to work with the options API. (Works fine using composition API).

What's giving me trouble specifically is the watcher. I've tried two different ways (and many more actually) but none of these seem to work. The watcher is never triggered:

<script>
export default {
  data(){
    return {
    }
  },
  props: ['options', 'list', 'itemKey', 'tag'],
  emits: ['choose', 'unchoose', 'start', 'end', 'add', 'update', 'sort', 'remove', 'filter', 'move', 'clone', 'change'],
  mounted(){
    this.$watch(
      () => {
          return this.$refs.containerRef
      },
      (val) => {
        console.log(val)
        alert('App $watch $refs.containerRef: ' + val)
      }
    )
  },
  unmounted(){
    if (this.$refs.sortable) {
      this.$refs.containerRef = null;
      this.$refs.sortable = null;
    }
  },
  watch: {
    containerRef(newDraggable, oldDraggable){
      if (newDraggable) {
        this.$refs.sortable = new Sortable(newDraggable, {
          ...props.options,
          group: "shared",
          onChoose: (event) => this.$emit("choose", event),
          onUnchoose: (event) => this.$emit("unchoose", event),
          onStart: (event) => this.$emit("start", event),
          onEnd: (event) => this.$emit("end", event),
          onAdd: (event) => this.$emit("add", event),
          onUpdate: (event) => this.$emit("update", event),
          onSort: (event) => this.$emit("sort", event),
          onRemove: (event) => this.$emit("remove", event),
          onFilter: (event) => this.$emit("filter", event),
          onMove: (event, originalEvent) => this.$emit("move", event, originalEvent),
          onClone: (event) => this.$emit("clone", event),
          onChange: (event) => this.$emit("change", event),
        });
      }
    }
  }
}
</script>

Any thoughts on how to implement the watcher using options?

And thanks for the great work, this has been super useful!

Found ts declaration file but could not be resolved.

I am using vscode 1.78.2 together with vue 3.2.47 and latest vite.

I installed latest sortablejs-vue3 (1.2.9) as per instructions and am seeing error below.

I do see node_modules/sortablejs-vue3/dist/src/components/Sortable.vue.d.ts and the referred to node_modules/sortablejs-vue3/dist/types/main.d.ts but do not understand the comment on his result could not be resolved when respecting package.json

Could not find a declaration file for module 'sortablejs-vue3'. '/Users/colinbester/SynologyDrive/vite/recipe-manager/node_modules/sortablejs-vue3/dist/sortablejs-vue3.es.js' implicitly has an 'any' type.
  There are types at '/Users/colinbester/SynologyDrive/vite/recipe-manager/node_modules/sortablejs-vue3/dist/types/main.d.ts', but this result could not be resolved when respecting package.json "exports". The 'sortablejs-vue3' library may need to update its package.json or typings.ts(7016)

My vite tsconfig.json is setup under compilerOptions to use moduleResolution: "bundler"

Assistance appreciated.

`onMove` incompatible with SortableJs

emit('onMove') does not have the desirable effect

In SortableJs, you are able to cancel a move by returning a value from onMove() call. However, because of the way the code is implemented right now, this functionality is completely disabled.

sortable.value = new Sortable(newDraggable, {
...props.options,
onChoose: (event) => emit("choose", event),
onUnchoose: (event) => emit("unchoose", event),
onStart: (event) => {
isDragging.value = true;
emit("start", event);
},
onEnd: (event) => {
// This is a hack to move the event to the end of the event queue.
// cf this issue: https://github.com/SortableJS/Sortable/issues/1184
setTimeout(() => {
isDragging.value = false;
emit("end", event);
});
},
onAdd: (event) => emit("add", event),
onUpdate: (event) => emit("update", event),
onSort: (event) => emit("sort", event),
onRemove: (event) => emit("remove", event),
onFilter: (event) => emit("filter", event),
// See https://github.com/MaxLeiter/sortablejs-vue3/pull/56 for context on `attrs`.
onMove: (event, originalEvent) => "onMoveCapture" in attrs ? (<(event: Sortable.MoveEvent, originalEvent: Event) => void>attrs.onMoveCapture)(event, originalEvent) : emit("move", event, originalEvent),
onClone: (event) => emit("clone", event),
onChange: (event) => emit("change", event),
});

Related issue vuejs/core#8865

The reason is because emit() does not return the value from the handler.

Here are some proposals

  • Use props instead of emits
  • Respect the SortableOption instead of always overwriting them
  • Wait until Vue updates emit behavior, and mention that this functionality doesn't work

Nested draggable children

Despite I've tried I'm not able to make it work with nested children. I've added :group prop but no luck so far.
So my question is: is this library able to handle nested children and can we swap children between parents?

Incorrect dom list with reactive array after drag

My code is like this:

<template>
  <Sortable :list="list" item-key="id" :options="options">
    <template #item="{ element }">
      <div class="draggable" :key="element.id">
        {{ element.name }}{{ element.id }}
      </div>
    </template>
  </Sortable>
</template>

<script setup lang="ts">
import { reactive } from "vue"
import { Sortable } from "sortablejs-vue3"

const list = reactive([
  {
    id: "111",
    name: "item1",
  },
  {
    id: "222",
    name: "item2",
  },
])

const options = {
  draggable: ".draggable",
  animation: 150,
  ghostClass: "ghost",
  dragClass: "drag",
  scroll: true,
  forceFallback: true,
  scrollSensitivity: 50,
  scrollSpeed: 10,
  bubbleScroll: true,
}
</script>

If I drag them, then modify list by splicepush or other methods, the dom list will be incorrect , some item could repeat, even if they have the same id.

For example, if I drag one of the item , and then remove every item in this reactive list, the dom dragged will still stay there. Then I push new item into the list, that Dom will still remain there even if it have the same id with new item

Custom delete events do not work

 <Sortable :list="taskList" class="table-wrapper-web" item-key="id" tag="div" :options="options" @add="addEntry"
            @update="moveEntryWithinList" @remove="removeNestedEntry">
            <template #item="{ element }">
                <div :data-parent-id="parentId" :data-entry-id="element.id" :data-entry-type="element.type" class="drawing-item">

                    <span class="drawing-item-copy" :class="[element.id == select ? 'drawing-row-item' : '']"
                        @click.stop="handleCopyItem(element)">
                        <icon :size="14">
                            <CopyDocument />
                        </icon>
                    </span>

                    <span class="drawing-item-delete" :class="[element.id == select ? 'drawing-row-item' : '']"
                        @click.stop="handleDeleteItem(element)">
                        <icon :size="14">
                            <Delete />
                        </icon>
                    </span>

                </div>
            </template>
        </Sortable>

const options = ref({
    handle: '.drawing-item',
    group: 'desgin',
    animation: 100,
    forceFallback: true,
    fallbackOnBody: true,
    ghostClass: "sortable-ghost"
})

Clicking the delete event inside the item does not respond, but fires the ghost event

Issues using with TransistionGroup

Great package. Thanks for your work. I'm having trouble using it with Vue3's Transition Group (https://vuejs.org/guide/built-ins/transition-group.html).

Using <Sortable> inside <transition-group> renders the sortable list inside a wrapper which breaks transistion-group. Specifying tag="transition-group" renders the tag but none of the transition-group functionality.

Am I missing something? Is there a work around?

Have created a fiddle. https://stackblitz.com/edit/vitejs-vite-jycoxf?file=src/App.vue

Cancelling Move does not work

In Sortable you can return false from a move event handler in order to cancel a drag operation:

// Event when you move an item in the list or between lists
	onMove: function (/**Event*/evt, /**Event*/originalEvent) {
		// Example: https://jsbin.com/nawahef/edit?js,output
		evt.dragged; // dragged HTMLElement
		evt.draggedRect; // DOMRect {left, top, right, bottom}
		evt.related; // HTMLElement on which have guided
		evt.relatedRect; // DOMRect
		evt.willInsertAfter; // Boolean that is true if Sortable will insert drag element after target by default
		originalEvent.clientY; // mouse position
		// return false; — for cancel
		// return -1; — insert before target
		// return 1; — insert after target
		// return true; — keep default insertion point based on the direction
		// return void; — keep default insertion point based on the direction
	},

However, in Vue this seems to be swallowed by the emit handling:

function emit$1(instance, event, ...rawArgs) {
    //[...]
    if (handler) {
        callWithAsyncErrorHandling(handler, instance, 6 /* ErrorCodes.COMPONENT_EVENT_HANDLER */, args);
    }
    const onceHandler = props[handlerName + `Once`];
    if (onceHandler) {
        if (!instance.emitted) {
            instance.emitted = {};
        }
        else if (instance.emitted[handlerName]) {
            return;
        }
        instance.emitted[handlerName] = true;
        callWithAsyncErrorHandling(onceHandler, instance, 6 /* ErrorCodes.COMPONENT_EVENT_HANDLER */, args);
    }
}

No return value is passed on to Sortable and therefore I cannot cancel. My move event callback looks like this:

function move(evt) {
    return !evt.to.classList.contains("no-drop");
}

Is there any trick to it, or does it not work right now? What I am trying to achieve is to have a list that I can drag out of, but not drag into. Is there any other way to get that behavior?

Edit: Also I noted that the event has a property "returnValue", but setting this to false in my callback also does not seem to work.

Allow itemKey to be a function

Hi,

I’d be nice if itemKey would also accept a function in the form of (item: any) => number | string | symbol .
I have a list of lists and the key is deferred from the first item of that list and itemKey can’t be a string in this case, as there is no attribute of the nested list that would qualify as the key.

I might be able to put together a pull request, but maybe you’re faster :). In any case thank you for your time!

Cheers

Konrad

typeError: t is not a constructor

Hi.

I used @vue/cli-service version 4.5.9 and couldn't build project because this lib uses optional-chaining syntax.
Babel loader with "@babel/plugin-proposal-optional-chaining" helped me, but I don't need extra loaders so decided to update @vue/cli-service and @vue/cli-plugin-typescript to "^5.0.8" and now I have such runtime error

image

any thoughts?

Issue swapping draggable elements

Hello,

I’m hoping to get some help with what I’m trying to implement.

I have two sections of tile slots with tiles inside, and need to be able to drag/move tiles to different tile slots. I’m treating each Sortable component as a tile slot and using the item template to render a draggable tile. Each tile slot can either have no tile or just a single tile. So for my use case, the list prop’s array should never have more than 1 element.

If a tile slot has a tile, it can either be locked or not locked. If it is locked, I’m passing in the SortableJS disable prop as true to the options prop. This works fine because when I drag tile B to a tile slot which has tile A locked, the on move handler is never fired, tile A does not move and tile B is returned to its original tile slot.

However, if tile A is not locked, I’m hoping to be able to swap the positions of tile A and tile B. I’m having two issues in this case:

  1. When dragging tile B over tile A, it looks like tile A gets pushed out of the tile slot. I don’t want this. (refer to screenshot e below)
  2. When I let go, there are now 2 B tiles in the tile slot, even though the list prop that’s passed down only contains one tile B. (refer to screenshot f)

Questions:

  1. Is there a way to prevent this from happening without setting the SortableJS disabled prop in the options prop? I was hoping I could return false in the move event handle to cancel the move (https://github.com/SortableJS/Sortable#options), and in the on end handler, emit an event to the parent component which would update the list prop, but cancelling the move doesn’t seem to work. The issue with setting the disabled prop is that the on end handler’s event.to object is then not correct.
  2. There seems to be a conflict with Vue trying to re-render the page and the library also manipulating the DOM at the same time, thus causing there to be two tiles in the single tile slot even though the Sortable list prop only has 1 item.
  3. I know SortableJS has a swap plugin, is there a way to enable that in sortablejs-vue3?

Thanks in advance!

Screenshots:

a)Initially with empty tile slots:
1-initially empty tile slots

b)Tile A placed in tile slot position 2, unlocked:
2-tile A unlocked

c)Tile A locked:
3-tile A locked

d)Trying to swap Tile B with Tile A when Tile A is locked, Tile A does not get pushed out (using the disabled prop):
4-trying to swap tiles when locked

e)Trying to swap Tile B with Tile A when Tile A is not locked, causing Tile A to get pushed out. This is before letting go of the drag:
5-trying to swap tiles when unlocked

f)After letting go of the drag, Tile A is correctly removed but Tile B is now duplicated in the tile slot when it shouldn't be:
6-after swapping

How to get access to item on event?

I didn't understand how can I access the item data inside the event? Tell me please

<script setup>
const changeCategoryIndex = async (element) => {
  // hot to get access to current item?
};

const changeServiceIndex = async (element) => {
  // hot to get access to current item and parent item?
};
</script>

<template>
          <Sortable
            :list="categories"
            item-key="categoryId"
            @end="changeCategoryIndex"
          >
            <template #item="{ element: category }">
                <div
                  :key="category.categoryId"
                >
                  <div>
                    {{ category.title }}
                  </div>

                <Sortable
                  item-key="serviceId"
                  :list="category.services"
                  @end="changeServiceIndex"
                >
                  <template #item="{ element: service }">
                    <div>
                      {{ service.title }}
                    </div>
                  </template>
                </Sortable>
              </div>
            </template>
          </Sortable>
</template>

Pinia state persistence

Apologies for this issue which seeks guidance more than raises code issues.

I have a list of objects in a Pinia store which I am accessing in the component via the standard storeToRefs(). These objects contain a property order which is used to specify the order within the list.

I first filter this list to remove an entry via a computed property like:

const filteredObjectList = computed({
  get() {
    return objectList.value.filter((obj) => {
      return obj.id != 0;
    })
  },
  set(newList) {
    console.log(newList)
  }
})

I have been able to produce the correct drag and drop behaviour via :list="filteredObjectList" item-key="order" and the list reorders properly. However the state does not seem to persist when the list is hidden and then shown again via a v-if clause. It is worth noting as well that the setter is never called.

Would you be able to provide some guidance on this non-persistence issue?

Undo a sort action?

I'm using this library for sorting a list, and I'm saving the sort order server-side. I do this by listening to the end event, looping through items between event.oldIndex and event.newIndex, and performing an upsert to the database setting the order field to the new index.

This works, but what do I do if there's a network error? How can I reorder the list back to the way it was before an element was moved? I'm kind of stumped because this version of Sortable doesn't have a value/modelValue property, only a list property. And this list's order seems to be stored internally within this Sortable component. Updating the list value does nothing. I assume it's read once at initialization, and then the component handles the list internally from there. That's fine, but how can I manually change the order of elements if I want to, such as in this case?

esm file must be of extension .mjs

tldr: vuejs/vitepress#1399 (comment)

hi, when component builds inside vitepress, it's fails with error:

✖ rendering pages...
build error:
 file:///Users/path-to-project/docs/.vitepress/.temp/SomeComponent.c214d190.js:4
import { Sortable } from "sortablejs-vue3";
         ^^^^^^^^
SyntaxError: Named export 'Sortable' not found. The requested module 'sortablejs-vue3' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'sortablejs-vue3';
const { Sortable } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:190:5)

to handle such cases with different environments, need to change the extension of the file from .es.js to .es.mjs in package.json and vite.config of this project.
checked locally with the this changes, project builds without errors and everything works

Thanks

Thanks!

Vue draggable broke, this is more light weight and better IMHO!

yarn install error

sortablejs-vue3 version:
1.0.0

Yarn version: 
  1.22.18

Node version: 
  14.19.3

Platform: 
  win32 x64

Trace: 
  Invariant Violation: expected hoisted manifest for "sortablejs-vue3#vue#@vue/server-renderer#@vue/compiler-ssr"
      at invariant (D:\Server\nodejs\nvm\v14.19.3\node_modules\yarn\lib\cli.js:2314:15)
      at _loop2 (D:\Server\nodejs\nvm\v14.19.3\node_modules\yarn\lib\cli.js:91022:9)
      at PackageHoister.init (D:\Server\nodejs\nvm\v14.19.3\node_modules\yarn\lib\cli.js:91092:19)
      at PackageLinker.getFlatHoistedTree (D:\Server\nodejs\nvm\v14.19.3\node_modules\yarn\lib\cli.js:48541:20)
      at PackageLinker.<anonymous> (D:\Server\nodejs\nvm\v14.19.3\node_modules\yarn\lib\cli.js:48552:27)
      at Generator.next (<anonymous>)
      at step (D:\Server\nodejs\nvm\v14.19.3\node_modules\yarn\lib\cli.js:310:30)
      at D:\Server\nodejs\nvm\v14.19.3\node_modules\yarn\lib\cli.js:328:14
      at new Promise (<anonymous>)
      at new F (D:\Server\nodejs\nvm\v14.19.3\node_modules\yarn\lib\cli.js:5301:28)

Unexpected behaviour when not removing from data array

Hi! Im not very familiar with sortablejs

const baseTasks : Array<{ id: Task['id'] }> = [ {id: '1'}, {id: '2'}, {id: '3'} ]
const taskList : Ref<Array<{id: Task['id'], removed?: boolean}>> = ref([]);

Im using the following add/remove handlers without removing the task from the list

function listOnAdd(event: SortableEvent): void {    
    const taskId = event.item.getAttribute('task-id');
    if (typeof taskId !== 'string') throw new Error('Invalid Task Id!');
    
    event.item.remove();
    taskList.value.push({id: taskId});
}

function listOnRemove(event: SortableEvent): void {
    const taskId = event.item.getAttribute('task-id');
    if (typeof taskId !== 'string') throw new Error('Invalid Task Id!');
    
    const taskIndex = taskList.value.findIndex(i => i.id === taskId);
    if (taskIndex === -1) throw new Error('Task not found!');
    
    taskList.value[taskIndex] = {id: taskId, removed: true}; // only mark them as 'removed'
    // taskList.value.splice(taskIndex, 1);
}

function listOnReset() {
    taskList.value = [...baseTasks];
}
 <button @click="listOnReset">reset</button>

 <Sortable
    ref="sortableElement"
    class="task-list"
    :list="taskList"
    item-key="id"
    :options="options"
    @add=     "listOnAdd"
    @remove=  "listOnRemove"
  >
    <template #item="{element}">
      <Task :task-id="element.id"/>
    </template>
  </Sortable>

The elements that are moved between categories, when reset, dont seem to be added again.
https://stackblitz.com/edit/recursive-template-refs-5ip6ao?file=src%2Fcomponents%2FTaskList.vue

23-10-2023-46

Is this correct behaviour? I'm a bit surprised that the elements are not behaving as a clone list

Dynamic Sortable options

Hello,
I'm trying to enable/disable sorting by using the component prop :options="dragOptions" with a computed object like so :

const dragOptions = computed(() => ({
	animation: 200,
	ghostClass: "ghost",
	disabled: !isSorting.value,
}));

However, dynamically changing the disabled property doesn't toggle sorting.
I found a way to "force" the update by changing the wrapping tag like so : :tag="isSorting ? 'div' : 'section'" but it's not a really clean solution.

e.preventDefault() not working?

I am trying to stop a drag from list A to list B (drags from B to A are allowed). I have tried handling both the move and the end events, but cannot prevent them:
function checkMove(e) { var c = e.cancelable; if (e.to.dataset.list == "startGrid") e.preventDefault(); }
the debugger clearly shows 'preventDefault' being reached, but the move still ocurs. This seems pretty basic; what am I doing wrong here?

Access to the sorted list

How can I access the sorted list' I'd like to store/retrieve it and I can't find how to d it.

Thank you.

way to get refs to components

I need to access something which is computed(() => {...}) inside the components i'm drag-and-dropping.

there doesn't seem to be any way to get my hands on a list of refs, like you would do with v-for.

is there a secret hidden way, or could such a feature be added?

Event onMove does not support the return value

From documentation SortableJS in onMove event I can return value to write some logic:

// Event when you move an item in the list or between lists
onMove: function (/**Event*/evt, /**Event*/originalEvent) {
  // Example: https://jsbin.com/nawahef/edit?js,output
  evt.dragged; // dragged HTMLElement
  evt.draggedRect; // DOMRect {left, top, right, bottom}
  evt.related; // HTMLElement on which have guided
  evt.relatedRect; // DOMRect
  evt.willInsertAfter; // Boolean that is true if Sortable will insert drag element after target by default
  originalEvent.clientY; // mouse position
  // return false; — for cancel
  // return -1; — insert before target
  // return 1; — insert after target
  // return true; — keep default insertion point based on the direction
  // return void; — keep default insertion point based on the direction
},

But I can't repeat it on this wrapper.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Other Branches

These updates are pending. To force PRs open, click the checkbox below.

  • Update dependency vue to v3.3.4

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/bundle-check.yml
  • actions/checkout v3
  • actions/setup-node v3
  • actions/upload-artifact v3
  • peter-evans/create-or-update-comment v2.1.1
.github/workflows/release.yml
  • actions/checkout v3
  • actions/setup-node v3
npm
package.json
  • sortablejs ^1.15.0
  • vue ^3.2.37
  • @types/node 18.14.2
  • @types/sortablejs 1.15.0
  • @vitejs/plugin-vue 4.0.0
  • prettier 2.8.4
  • terser 5.16.5
  • typescript 4.9.5
  • vite 4.1.4
  • vue-tsc 1.2.0
  • sortablejs ^1.15.0
  • vue ^3.2.25

  • Check this box to trigger a request for Renovate to run again on this repository

Can not use TransistionGroup

Thanks for your great package, I have encountered a difficulty when trying to use the TransitionGroup. It seems that there's a compatibility issue or perhaps I might be missing something.

Managing state when moving items between lists

Thanks again for this lib.

I have several lists on my page, and want to be able to drag items between lists. For this, I give every list the same sortable group option.

This is how I am trying to manage the state when dragging an item between lists:

  1. use remove event to remove item from the state
  2. use add event to add the item back to the state in its new location

My state is updating just fine, however, the orginal DOM element is moved to the new list (and not removed from the DOM). This results in duplicates (because my state also creates a new element).

Currently, it looks like my options are to either:

  1. manually remove the DOM element with event.item.remove() OR
  2. force re-render my component to keep the state in sync

Both of these seem hacky - is there a better approach?

Uncaught TypeError: Cannot read properties of null (reading 'isCE')

Hello,

Apologies if this is incredibly stupid, but I have been digging through all available resources and stack overflow answers, and haven't been able to work out what's going on here.

Uncaught TypeError: Cannot read properties of null (reading 'isCE')
at renderSlot (runtime-core.esm-bundler.js:2812:1)
at eval (sortablejs-vue3.es.js:102:1)
at normalizeChildren (runtime-core.esm-bundler.js:7001:1)
at createBaseVNode (runtime-core.esm-bundler.js:6812:1)
at _createVNode (runtime-core.esm-bundler.js:6889:1)
at createVNodeWithArgsTransform (runtime-core.esm-bundler.js:6766:1)
at createBlock (runtime-core.esm-bundler.js:6738:1)
at Proxy.eval (sortablejs-vue3.es.js:97:1)
at renderComponentRoot (runtime-core.esm-bundler.js:815:1)
at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js:5704:1)

Here is the component, which was working fine before I tried using Sortable.:

<script>
// import SortableRow from "@/components/SortableRow.vue";
import {Sortable} from "sortablejs-vue3";

export default {
  name: 'SortableTable',
  components: {
    // SortableRow,
    Sortable,
  },
  props: {
    report: {
      type: Array,
      required: true
    }
  }
}
</script>

<style scoped>
  /* ... styles ... */
</style>

<template>
  <table>
    <thead>
      <tr>
        <th>Handle</th>
        <th>Type</th>
        <th>Dataset</th>
        <th>Label</th>
        <th>Disags</th>
        <th>Chart</th>
      </tr>
    </thead>
    <Sortable :list="report" item-key="id" tag="tbody">
      <template #item="value">
        <tr class="draggable" :key="value.id">
          <td><i class="fa-solid fa-bars"></i></td>
          <td>{{ value.type }}</td>
          <td></td> <!-- dataset -->
          <td>{{ value.label }}</td>
          <td></td> <!-- disags -->
          <td></td> <!-- chart -->
        </tr>
      </template>
    </Sortable>
  </table>
</template>

and this is the main App.vue:

<template>
  <sortable-table :report="report"></sortable-table>
</template>

<script>
import SortableTable from "@/components/SortableTable.vue";
import { report } from "@/main";

export default {
  name: 'App',
  data() {
    return {
      report: report
    }
  },
  components: {
    SortableTable
  }
}
</script>

<style>
  /* ... styles ... */
</style>

I'm really struggling to work out what's going on here, and any support you can offer would be greatly appreciated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.