npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vue2-dragula-test

v0.0.4

Published

Vue 2 wrapper for dragula

Downloads

6

Readme

vue2-dragula

:ok_hand: Drag and drop so simple it hurts

Vue wrapper for dragula drag'n drop library, based on vue-dragula by @Astray-git.

This library has been refactored, upgraded and extended with powerful new features for use with Vue 2.

Call for help: copy error

This library has a long standing issue with the copy operation, resulting in items being inserted twice in the target container.

I have tried to debug it thorougly but with no success so far. I suspect it has to do with the Vue2 override of Array splice method, used in the ModelManager and the correct use of the Vue update queue.

You can try the ImmutableModelManager and see if that works better as it will return a new immutable array with a new pointer on each change.

$set for modifying objects in array for reactivity

Vue.set(this.model, changedModel)

Here a JSFiddle to play with

Please help fix this bug!

You can also try a simple array example in a Vue component, with buttons and handlers to simulate each of the effects (on underlying array model) for the drag effects:

  • copy
  • move

To better help track and fix the problem with the way Vue updates arrays.

insertAt(index, insertModel) {
  const splicedModel = this.model.splice(index, 0, insertModel)
  const modelAfterInsert = this.model
  return splicedModel
}

Currently the splicedModel returns an empty array [] and modelAfterInsert the same (unmodified) array as before the splice. Yet, copy (or Vue?) still ends up inserting the item twice in the UI

Copy: ensure clone

When making a copy error we need to ensure we are not reusing the same reference in the two container models. We need to clone the value first.

Otherwise, if "copy" is deleted or modified in one container, it will be deleted/modifed in both due to shared reference.

dropModelTarget(dropElm, target, source) {
  let notCopy = this.dragElm === dropElm
  let dropElmModel = notCopy ? this.dropElmModel() : this.jsonDropElmModel()
  if (notCopy) {
    this.notCopy()
  }
  // ...
}

jsonDropElmModel() {
  // ...
  let jsonStr = JSON.stringify(stringable || model)
  return JSON.parse(jsonStr)
}

So we should be handling this correctly!?

Call for care taker or more contributors

I haven't been using Vue2 much for the past year, so could use one or more contributors to be take care of this project and keep it up to date. Thanks!

Overview

  • Works with Vue 2
  • More flexible and powerful than original (Vue 1) plugin
  • Removed concept of bags. Reference named drakes directly
  • Vue2 demo app

See Changelog for details.

Demo

See vue2-dragula demo

Gotchas

Beware of Vue 2 reactivity issues when working with Arrays.

See post: reactivity in Vue2 vs Vue3

Use Vue.set or vm.$set to explicitly set/initialize an Array on a component and notify Vue about it.

Beware of pointers and instances which can lead to bugs where a service is triggered multiple times, leading to duplication of events.

Installation and configuration

npm

npm install vue2-dragula --save

yarn

yarn add vue2-dragula

Vue configuration

import Vue from 'vue'
import { Vue2Dragula } from 'vue2-dragula'

Vue.use(Vue2Dragula, {
  logging: {
    service: true // to only log methods in service (DragulaService)
  }
});

Dragula's CSS, which provides visual feedback for drag effects, is not included in this package and must be imported or provided in your app.

import 'dragula/dist/dragula.css'

Documentation

For additional documentation, see the docs folder

Dragula events and drag effects

See Dragula events and drag effects

Template Usage

<div class="wrapper">
  <div class="container" v-dragula="colOne" drake="first">
    <!-- with click -->
    <div v-for="text in colOne" :key="text" @click="onClick">{{text}} [click me]</div>
  </div>
  <div class="container" v-dragula="colTwo" drake="first">
    <div v-for="text in colTwo" :key="text">{{text}}</div>
  </div>
</div>

NOTE: Since Vue 2.x, having the :key attribute when using v-for is reqired.

API

You can access the global app service via Vue.$dragula.$service or from within a component via this.$dragula.$service (recommended for most scenarios).

You can also create named services for more fine grained control.

Service configuration

Set dragula options

Use service.options(name, options) to configure service options

// ...
new Vue({
  // ...
  created () {
    const service = Vue.$dragula.$service
    service.options('my-drake', {
      direction: 'vertical'
    })
  }
})

find drake by name

Use service.find(name) to return a named drake instance registered with the service.

Event handlers via event bus

See drake events

Use service.eventBus.$on to define drake event handlers

service.eventBus.$on('drop', (args) => {
  console.log('drop: ' + args[0])
})

Development

npm scripts included:

  • npm run build to build new distribution in /dist
  • npm run dev run example in dev mode
  • npm run lint lint code using ESlint

Vue 2 demo app

The API in depth

Access this.$dragula in your created () { ... } life cycle hook of any component which uses the v-dragula directive.

Add a named service via this.$dragula.createService({name, eventBus, drakes}) factory method. Initialise each service with the drakes you want to use.

$dragula

$dragula API:

  • createService({name, eventBus, drakes}) : to create a named service
  • createServices({names, ...}) : to create multiple services (names list)
  • on(handlerConfig = {}) : add event handlers to all services
  • on(name, handlerConfig = {}) : add event handlers to specific service
  • drakesFor(name, drakes = {}) : configure a service with drakes
  • service(name) : get named service
  • .services : get list of all registered services
  • .serviceNames : get list of names for all registered services

DragulaService

The DragulaService constructor takes the following deconstructed arguments. Only name and eventBus are required.

Note: You don't normally need to create the DragulaService yourself. Use the API to handle this for you.

class DragulaService {
  constructor ({name, eventBus, drakes, options}) {
    ...
  }
  // ...
}

Drakes are indexed by name in the drakes Object of the service. Each key is the name of a drake which points to a drake instance. The drake can have event handlers, models, containers etc. See dragula options

Binding models to draggable elements

Please note that vue-dragula expects the v-dragula binding expression to point to a model in the VM of the component, ie. v-dragula="items"

When you move the elements in the UI you also (by default) rearrange the underlying model list items (using findModelForContainer in the service). This is VERY powerful!

Note that special Vue events removeModel, dropModel and insertAt are emitted as model items are moved around.

this.name, el, source, this.dragIndex
  'my-first:removeModel': ({name, el, source, dragIndex, sourceModel}) => {
    // ...
  },
  'my-first:dropModel': ({name, el, source, target, dropIndex, sourceModel}) => {
    // ...
  },
  'my-first:insertAt': ({indexes, models, elements}) => {
    // ...
  },
  • el main DOM element of element (f.ex element being dropped on)
  • source is the element being dragged
  • target is the element being dragged to
  • dragIndex and dropIndex are indexes in the VM models (lists)

If you need more advanced control over models (such as filtering, conditions etc.) you can use watchers on these models and then create derived models in response, perhaps dispatching local model state to a Vuex store. We recommend keeping the "raw" dragula models intact and in sync with the UI models/elements.

Event delegation

Each drake is setup to delegate dragula events to the Vue event system (ie. $emit) and sends events of the same name. This lets you define custom drag'n drop event handling as regular Vue event handlers.

A named service my-first emits events such as drop and my-first:drop so you can choose to setup listeneres to for service specific events!

There are also two special events for when the underlying models are operated on: removeModel and dropModel. These also have service specific variants.

Advanced concepts

Logging

See Logging

Model mechanics

See Model mechanics

Customization

See Customization

Drake mechanics and configuration

See Drake mechanics and configuration

Adding Drag Effects

See Drag Effects

Time travel

See Time travel

VueX integration

See VueX integration example

Please help add more examples.

Wiki with Bonus Recipes

Please see the Wiki

Recipes

Auto-sorted lists

Add an Rx Observable or a watch to your model (list) which triggers a sort of a derived (ie. immutable) model whenever it is updated. You should then display the derived model in your view. Otherwise each sort operation would trigger a new sort.

License

MIT Kristian Mandrup 2016