astray-git / vue-dragula Goto Github PK
View Code? Open in Web Editor NEW:ok_hand: Drag and drop so simple it hurts http://astray-git.github.io/vue-dragula
License: MIT License
:ok_hand: Drag and drop so simple it hurts http://astray-git.github.io/vue-dragula
License: MIT License
I've ben working on a huge refactoring and extension of the plugin vue2-dragula and a demo app: vue2-dragula-demo
Would love if some of you guys would test it out and help make it the best drag'n drop plugin for Vue2.
Note that the demo app currently only uses the global service API. Please help make this a great plugin for Vue2 and test the rest of the API. Cheers :)
Hi,
In my drag n drop operation, when released, I make an AJAX request.
If AJAX Fails, I will need to get my item back to where it was.
Is there any available cancel() method to achieve that???
This is some jade code iterating through an array of objects which themselves contain arrays that are to be used as source model.
.NewElements(v-dragula='elementGroup.elements' bag='content' v-for='elementGroup in elements')
h3 {{elementGroup.
.Element(v-for='element in elementGroup.elements')
When I am dragging this to another container, with the copy
option enabled, the data that is inserted in the targetModel equals the correct array entry in the sourceModel + 1.
Changing line dist/vue-dragula.js:1186
from
var dropElmModel = notCopy ? sourceModel[dragIndex] : JSON.parse(JSON.stringify(sourceModel[dragIndex]));
to
var dropElmModel = notCopy ? sourceModel[dragIndex] : JSON.parse(JSON.stringify(sourceModel[dragIndex - 1]));
fixes it for me, but I guess is breaking things at some other point.
In order to define Dragula options, I added a created
function to my Vue instance. However, Vue.VueDragula
is not available like shown in the docs.
So the example below does not work:
...
new Vue({
...
created: function () {
Vue.VueDragula.options('my-bag', {
direction: 'vertical'
})
}
})
How can I configure dragula now?
created
hookTo follow one-way data flow in Vuejs 2, model value will not be updated automatically on drake events inside the directive. Updated model will be emitted with events.
Using event bus allow us handle events directly in other components. And we need to update models manually.
For "in component" drag&drop we just update model, but for "cross-component" drop&drop(or copy) actions, target and source needs to be update separately.
Currently a dropTarget
is exposed in event payload:
eventTarget = {
el: target, // Target element
model: targetModel, // updated model of target component
expression: targetExpression // the expression for directive
}
Here's a simple example:
function updateModel (vm, dropTarget, dropSource) {
vm[dropSource.expression] = dropSource.model
if (dropTarget.el === dropSource.el) { return }
vm[dropTarget.expression] = dropTarget.model
}
Please try with the new version and leave feedbacks
I think changing Vue.vueDragula
to Vue.dragula
for to global settings object would be a nice tweak as it is more readable.
Super minor detail but am a fan of clean readable code.
As Vuejs is data based, it would be more apropriate to store all items in one array, and specify the bucket (column) they are in with a property. It's the same direction as vuelidate took over vee-validate. This has to be two-way synced, so if I set the .bucket property of an item, it should be moved to the apropriate bucket/column in the interface, and if I drag them around, the .bucket property shall be updated. Is this possible or planned? The current setup makes this compplicated.
Hi,
I created the listeners for drop events :
Vue.vueDragula.eventBus.$on("drop", function (args) {...
I add the listener when the component is mounted, now I want to remove the listener when its destroyed.
How can I remove the listeners.
drake.destroy is the original method, I tried the following, but it didnt work:
Vue.vueDragula.destroy()
or
var bag = Vue.vueDragula.find("questions-bag"); bag.drake.destroy();
Sorry if this is another noob question, but I'm really struggling to piece this together from your example page, docs, and example files.
Notice that if you collapse / expand groups after dragging, the components are effectively reset -- the data isn't actually changed. I assume that this is because I don't have the v-dragula
binding set correctly. I've tried a number of different values for this including:
group.items
in my example)In this case, I would expect the second item there to be the correct one, as the code seems to be doing some splicing logic (which I was keyed into by incorrectly using a string identifier as mentioned). It seems that this library is attempting to manipulate the data array backing it, but perhaps this doesn't work in the case that you have a multi-level component or something?
Hopefully my sample makes sense to demonstrate the issue, if not I can try to make it more clear.
If I try and set any of the options such as moves or invalid the functions are not working.
I noticed when debugging the vue-dragula code the option gets removed before it makes it in as an option to the dragula function. Example Code:
Vue.vueDragula.options('my-bag', { moves: function (el, container, handle) { return handle.classList.contains('dragHandle'); }, direction: 'vertical' })
vue-dragula.js?c9f2:1448 Uncaught ReferenceError: msg is not defined
if (this.find(name)) {
this.log('existing drakes', this.drakeNames);
var errMsg = 'Drake named: "' + name + '" already exists for this service [' + this.name + ']. \n Most likely this error in cause by a race condition evaluating multiple template elements with \n the v-dragula directive having the same drake name. Please initialise the drake in the created() life cycle hook of the VM to fix this problem.';
this.error(msg);<<<<<<<<<<<<
}
Is there a way to access the Dragula API directly? I need to cancel a drop when certain conditions are met and can't find a way currently.
Thanks!
I am trying to figure out how to access the canMove method from Dragula. https://github.com/bevacqua/dragula#drakecanmoveitem
I would like to define a condition to determine if an element is allowed to be moved. I have tried the following:
Vue.vueDragula.find('rules').drake.canMove((item) => {
return false;
});
Any idea how this would be done in Vue? Thank you.
When creating multiple directives with the same bag, the following error is thrown...
<div class="wrapper">
<div class="container" v-dragula="colOne" bag="first-bag">
<div v-for="text in colOne" @click="onClick">{{text}} [click me]</div>
</div>
<div class="container" v-dragula="colTwo" bag="first-bag">
<div v-for="text in colTwo">{{text}}</div>
</div>
</div>
Uncaught Error: Bag named: "test" already exists.
Could you possible provide an example of how to use a handle to initiate the dragging? Some thing along the lines of the second to last Dragula example?
I'm new to Github, so maybe I'm missing something, but it looks like v1.0.3 is in the v1.0.4 release.
I encountered a bug when using copy: true
. If you drop something, it will be created twice.
I think this is because the model is changed and the gu-transit element is inserted as well. That's why we then have two occurences of the same object, while only one of them is linked to the model
demo:
http://46bb3f4c.ngrok.io/
If you point me in the right direction, that would be great and I will submit a PR. Thanks ahead.
This script fails with an error:
var Vue = require('vue');
var VueDragula = require('vue-dragula');
Vue.use(VueDragula);
Therefore, can't get vue-dragula running.
A new version of Dragula got released, which enabled settings for drag detection offset (slideFactorX, slideFactorY)
If the dependency could get updated to the latest version, that would be nice.
Based on #19 (comment), indeed you cannot seem to reorder properly within the same bag.
I'm not yet sure if this is a Vue 2.0 issue or a vue-dragula issue. I'm trying to investigate, but I'm not that familiar with either projects.
I'm also having trouble creating a small example, so please help me out @Astray-git if you can
When I drag into another container, the HTML element will be added class scale-leave
but never be removed.
<template>
<div class="page-test">
<div v-for="c in categories">
<p>{{c.name}}</p>
<ul v-dragula="c.list">
<li v-for="item in c.list" transition="scale">{{item}}</li>
</ul>
</div>
</div>
</template>
<script>
export default {
data () {
return {
categories: [{
_id: '0000000001',
name: 'in progress',
list: ['111', '222']
}, {
_id: '0000000002',
name: 'plan',
list: ['333']
}]
}
}
}
</script>
<style lang="stylus">
.page-test
.scale-transition
overflow: hidden
height: 38px
transition: height .2s
.scale-enter,.scale-leave
height: 0
</style>
I have a slightly more complex use case where i am passing functions to some of the dragula options which requires knowledge of the container elements.
Normally you would define options globally for plugins in Vue but when faced with this use case, it is not possible anywhere other than in the component using this directive.
To gain access to Vue.vueDragula, i needed to make the following tweak to my code...
Vue.prototype.vueDragula = Vue.vueDragula;
Allowing access to the plugin within components which was previously not possible. Then i could define the options for a container as per usual.
let filterContainer = this.$els.filters;
let activeContainer = this.$els.attached;
this.vueDragula.options('filters', {
removeOnSpill: true,
revertOnSpill: true,
direction: 'vertical',
copy: (element, origin) => {
return origin === filterContainer;
},
accepts: (element, target) => {
return target === activeContainer;
}
});
What is not mentioned in the documentation is this creates a new dragula instance under the hood and as a result doesn't carry over any containers should the service already exist.
let filterContainer = this.$els.filters;
let activeContainer = this.$els.attached;
this.vueDragula.options('filters', {
containers: [
filterContainer,
activeContainer
],
removeOnSpill: true,
revertOnSpill: true,
direction: 'vertical',
copy: (element, origin) => {
return origin === filterContainer;
},
accepts: (element, target) => {
return target === activeContainer;
}
});
After adding those in, it was using my options finally but now the library started falling apart and becoming almost unusable.
TL;DR - the library is hard to use for these kinds of use cases not to mention buggy which is a real shame.
Just tested a basic setup with vue 2.2.4 and webpack and gives me failed to resolve directive. Is this supported in 2.2.4 or am I missing something? Thanks
<template>
<div>
<div class="wrapper">
<div class="container" v-dragula="colOne" bag="first-bag">
<div v-for="text in colOne" :key="text">{{text}}</div>
</div>
<div class="container" v-dragula="colTwo" bag="first-bag">
<div v-for="text in colTwo" :key="text">{{text}}</div>
</div>
</div>
</div>
</template>
<script>
import Vue from 'Vue'
import VueDragula from 'vue-dragula'
Vue.use(VueDragula)
export default {
name: 'index',
data: () => {
return {
colOne: [
'You can move these elements between these two containers',
'Moving them anywhere else isn"t quite possible',
'There"s also the possibility of moving elements around in the same container, changing their position'
],
colTwo: [
'This is the default use case. You only need to specify the containers you want to use',
'More interactive use cases lie ahead',
'Another message'
],
categories: [
[1, 2, 3],
[4, 5, 6]
],
copyOne: [
'Lorem ipsum dolor sit amet, consectetuer adipiscing elit.',
'Aenean commodo ligula eget dolor. Aenean massa.'
],
copyTwo: [
'Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.',
'Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem.'
]
}
},
created: function () {
Vue.vueDragula.options('third-bag', {
copy: true
})
},
ready: function () {
var _this = this
Vue.vueDragula.eventBus.$on(
'drop',
function (args) {
console.log('drop: ' + args[0])
console.log(_this.categories)
}
)
Vue.vueDragula.eventBus.$on(
'dropModel',
function (args) {
console.log('dropModel: ' + args)
console.log(_this.categories)
}
)
}
}
</script>
I found that when using <input>
, the focus is lost on model update. On every key stroke the focus is lost and I have to click back into the input for every subsequent keystroke.
It doesn't happen on native Dragula from what I can tell.
<div class="container" v-dragula="colOne" bag="first-bag">
<div v-for="(i, text) in colOne" >
{{text}}[click me]
<input v-model="colOne[i]"/>
</div>
</div>
Currently I'm settings options for vue-dragula in the ready callback of the main Vue file, like so:
var Vue = require('vue');
Vue.use(require('vue-dragula'));
new Vue({
el: '#app',
components: {
'categories': require('./components/categories.vue'),
}
data: {
// some data...
},
created: function () {
Vue.vueDragula.options('categories', {
// options...
});
}
});
But in another component, I have an update function for the categories, which requires me to re-initialize vue-dragula so new (or removed) containers are taken into account. In this case the categories are the bags/containers.
export default {
data: function () {
return {
// some data...
};
},
methods: {
saveCategories: function () {
// save categories to database
// use this.$set('categories', response.data.categories); so update categories data of Vue instance
// dragging doesn't anymore, re-init?
Vue.vueDragula.options('categories', function () {
// options again...
});
}
}
}
How can I access Vue.vueDragula.options
inside of a components method? this
doesn't work, and I can't find anything related on Vue itself or vue-dragula.
This is probably not really an issue, but maybe the docs can be updated if you know how to do something like this.
I used vue-dragula
in my project for the drag & drop list requirement.
It's worked perfect. But I have the below error at that hold element remove time.
Error in directive dragula update hook: "TypeError: Cannot read property 'drake' of undefined"
My code sample below
(template HTML code)
<ul v-dragula="dragDatas" bag="action-bag">
<li v-for="(drDatas, drIndex) in dragDatas" :key="drDatas.id">{{drDatas.name}}</li>
</ul>
(Script code)
import 'vue-dragula/styles/dragula.css';
created () {
Vue.vueDragula.options('action-bag', {
invalid: function (el, handle) {
return // CONDITION BASED
}
});
},
mounted () {
const self = this;
Vue.vueDragula.eventBus.$on('drop', async function ([bag, curElmt, allElmts]) {
// drop event based functionalities
})
}
I think this error is Vue.vueDragula.eventBus.$on
event listener error.
If anyone have this solution Kindly share me
I do:
Vue.vueDragula.eventBus.$on("dropModel", ...)
But that event is never fired.
I'm new to both Vue and (Vue-)Dragula, so maybe I'm missing something obvious here. I've created a structure with container components that contain headers and then a list of draggable item components.
Vue.component('container', {
props: [ 'group' ],
data: function() {
return {
expanded: false
}
},
methods: {
onClick: function() {
this.expanded = !this.expanded;
}
},
template: '\
<div class="group-container" @click="onClick"> \
<div class="group-container-header">+ {{group.description}}</div> \
<div class="group-container-rows" v-if="expanded" v-dragula="group.items" bag="items-bag"> \
<row \
v-for="item in group.items" \
:item="item" \
:key="item.id" /> \
</div> \
</div>'
});
When I drag, I'm seeing the element I'm dragging end up at the bottom of the list outside of a container, which isn't desirable, but seems to be consistent with the dragula documentation mentioning the default behavior is document.body
. I assume this is because I have something misconfigured... am I missing something in my simple example here?
Here's a runnable sample -- https://jsfiddle.net/shortstuffsushi/a8k941xm/
Hi, I'm using this in a project and it's cool - thanks! I'm having a problem though when moving an item from a list to another where the drag and drop works fine, but the underlying Vue data is not updated accordingly. If I reorder items within the same list instead, the Vue data is updated automatically as I can see with the Chrome dev tools.
Any idea? Thanks in advance.
Is there any plan on supporting new version 2.0 of Vue.js ?
I am using dropModel
event but there is no argument about the index.
I am trying to get the index like that:
Vue.vueDragula.eventBus.$on('dropModel', ([bag, el, target, source]) => {
const index = Array.prototype.indexOf.call(target.children[i], el)
})
But the index always is -1, because the new element from target is not equal to the old element from source (More than 2 containers), it's a new object.
BTW, Is there any way to get the item from v-for array? Not the HTML element.
On drop when copy is "on" a TypeError
is thrown in case the source model contains cyclic references. (My model is a tree structure where the nodes have a "parent" reference.)
When vue-dragula builds the target model for the drop-model
event it clones the source model by executing:
JSON.parse(JSON.stringify(sourceModel[dragIndex]))
The TypeError
is thrown by JSON.stringify
. By default JSON.stringify
does not support cyclic references.
A solution would be if vue-dragula would offer an option to let the user configure the "replacer function" (resp. the whitelist array) to be passed as the 2nd argument to JSON.stringify
.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
This way the user would get an opportunity to strip the problematic (= cyclic) model properties for stringification.
I'm using Vuejs 2 and vue-dragula 2.0.0-alpha.1 which worked fine until I added the cyclic model reference.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.