vue-dragula
vue-dragula copied to clipboard
WIP make example work with Vue 2.x
- Added
Development
section in Readme on how to usenpm
scripts included. - Advised on how to run example via python simple http server
- Tried to port example Vue app to Vue2, so far no luck - I get strange exception on
ready
Please help me out, I need this for Vue2 app!! :)
Hitting all kinds of road blocks with current example. I decided to create a clean Vue2 app with using vue init
with webpack template:
https://github.com/kristianmandrup/vue2-dragula-demo
Please help make it work :) IT references my current refactor branch. Feel free to fork and patch as needed...
I got my demo working :) I uses this exact branch!
Vue 2 with Dragula! Now we just need to integrate some smart handles!!!
I was somehow still referencing the old version of vue-dragula
in my demo project. Now it works, except I get a strange error:
Error: Bag named: "third-bag" already exists. at DragulaService.add
So this is related to the DragulaService
from vue-dragula
. The template html is the same, so what gives?! Please help out fix this bug!
add (name, drake) {
console.log('Dragula: add', name)
let bag = this.find(name)
if (bag) {
throw new Error('Bag named: "' + name + '" already exists.')
}
I tried to fix the json
filter causing a problem by mirroring the first-bag
pattern
<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">
<span class="handle">+</span>
<span>{{text}}</text>
</div>
</div>
</div>
But in this case it is not allowed. Beats me how to use these bags the right way :P
<label>Copy between containers</label>
<div class="wrapper">
<div class="container" v-dragula="copyOne" bag="third-bag">
<div v-for="text in copyOne" track-by="$index">{{text}}</div>
</div>
<div class="container" v-dragula="copyTwo" bag="third-bag">
<div v-for="text in copyTwo" track-by="$index">{{text}}</div>
</div>
</div>
But it turns out, it is caused by adding this drag
handler, which has nothing to do with "third-bag", it just happens to be the last bag I guess?
this.$dragula.eventBus.$on(
'drag',
function (el, container) {
console.log('drag: ', el, container)
// el.className = el.className.replace('ex-moved', '')
}
)
Perhaps the problem is more related to me not understanding the initiation and hot reload process!? When I reload, the component is mounted again, but memory still has old registration and so there is a conflict!? Please I beg you, help me understand this!
So as I see it, there is only ONE DragulaService
instance for Vue
export default function (Vue, options = {}) {
const service = new DragulaService(Vue)
When we bind, we get the bagName
of any element which has a data attribute bag
const bagName = vnode
? vnode.data.attrs.bag // Vue 2
: this.params.bag // Vue 1
We then lookup the bag in the service singleton
const bag = service.find(name)
and then we add, which of course causes conflict when we have two or more elements with the same bag attribute!!! so what is the correct way to configure this example!?
service.add(name, drake)
service.handleModels(name, drake)
Looks like the problem is that there is one global singleton service shared by the directive instances. Needs a redesign to make it one service per directive instance so they an have separate configs and don't conflict on bag names!! I wrote my thoughts and understanding in my demo app.
I think I finally have a sufficient understanding of the main problems with the current design and how to fix it with a more "modular" redesign. Described this in Readme of demo app.
Perhaps we could have an API where $dragula
can be used to create
an new service with it's own eventBus
, a set of bags
+ containers
and event handlers for events on that bus.
let customContainer = document.getElementById('left-container')
let serviceTwo = this.$dragula.create({
containers: ['colOne', 'colTwo', customContainer],
bags: ['second-bag']
}).on({
drop (el, container) {
console.log('drop: ', el, container)
}
...
})
let serviceThree = this.$dragula.create({
containers: ['copyOne'],
bags: ['third-bag']
}).on({
drop (el, container) {
console.log('drop: ', el, container)
}
...
})
In our directive, bind
has access to the context (ie. container component) via the vnode
argument and hence
vnode.context
Vue.directive('dragula', {
params: ['bag'],
bind: function bind(container, binding, vnode) {
We could have the element with the directive register with a $dragula
DragulaService
of that name.
console.log('can bind to $dragula', name, vnode.context.$dragula)
Trying to add various extensions to make it more flexible dev branch it works and looks very good!!!