vue-dragula icon indicating copy to clipboard operation
vue-dragula copied to clipboard

WIP make example work with Vue 2.x

Open kristianmandrup opened this issue 8 years ago • 7 comments

  • Added Development section in Readme on how to use npm 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!! :)

kristianmandrup avatar Nov 11 '16 14:11 kristianmandrup

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...

kristianmandrup avatar Nov 11 '16 15:11 kristianmandrup

I got my demo working :) I uses this exact branch!

Vue 2 with Dragula! Now we just need to integrate some smart handles!!!

kristianmandrup avatar Nov 11 '16 18:11 kristianmandrup

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', '')
        }
      )

kristianmandrup avatar Nov 12 '16 08:11 kristianmandrup

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)

kristianmandrup avatar Nov 12 '16 08:11 kristianmandrup

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.

kristianmandrup avatar Nov 12 '16 09:11 kristianmandrup

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)

kristianmandrup avatar Nov 12 '16 09:11 kristianmandrup

Trying to add various extensions to make it more flexible dev branch it works and looks very good!!!

kristianmandrup avatar Nov 12 '16 11:11 kristianmandrup