NgxDragDrop
Demo
npm install ngx-drag-drop --save
Angular directives for declarative drag and drop using the HTML5 Drag-And-Drop API
- sortable lists by using placeholder element (vertical and horizontal)
- nestable
- dropzones optionally support external/native draggables (img, txt, file)
- conditional drag/drop
- typed drag/drop
- utilize EffectAllowed
- custom CSS classes
- touch support by using a polyfill
- AOT compatible
Port of angular-drag-drop-lists but without the lists :wink:
This has dropzones
though :+1:
The idea is that the directive does not handle lists internally so the dndDropzone
can be general purpose.
Upcoming version release
Currently the next version including some performance optimizations is pending. See the CHANGELOG for details.
You can try it out by installing the next
version.
npm install ngx-drag-drop@next --save
Usage
app.component.html
<div [dndDraggable]="draggable.data"
[dndEffectAllowed]="draggable.effectAllowed"
[dndDisableIf]="draggable.disable"
(dndStart)="onDragStart($event)"
(dndCopied)="onDraggableCopied($event)"
(dndLinked)="onDraggableLinked($event)"
(dndMoved)="onDraggableMoved($event)"
(dndCanceled)="onDragCanceled($event)"
(dndEnd)="onDragEnd($event)">
<div *ngIf="draggable.handle"
dndHandle>HANDLE
</div>
draggable ({{draggable.effectAllowed}}) <span [hidden]="!draggable.disable">DISABLED</span>
<div dndDragImageRef>DRAG_IMAGE</div>
</div>
<section dndDropzone
(dndDragover)="onDragover($event)"
(dndDrop)="onDrop($event)">
dropzone
<div style="border: 1px orangered solid; border-radius: 5px; padding: 15px;"
dndPlaceholderRef>
placeholder
</div>
</section>
app.component
import { Component } from '@angular/core';
import { DndDropEvent } from 'ngx-drag-drop';
@Component()
export class AppComponent {
draggable = {
data: "myDragData",
effectAllowed: "all",
disable: false,
handle: false
};
onDragStart(event:DragEvent) {
console.log("drag started", JSON.stringify(event, null, 2));
}
onDragEnd(event:DragEvent) {
console.log("drag ended", JSON.stringify(event, null, 2));
}
onDraggableCopied(event:DragEvent) {
console.log("draggable copied", JSON.stringify(event, null, 2));
}
onDraggableLinked(event:DragEvent) {
console.log("draggable linked", JSON.stringify(event, null, 2));
}
onDraggableMoved(event:DragEvent) {
console.log("draggable moved", JSON.stringify(event, null, 2));
}
onDragCanceled(event:DragEvent) {
console.log("drag cancelled", JSON.stringify(event, null, 2));
}
onDragover(event:DragEvent) {
console.log("dragover", JSON.stringify(event, null, 2));
}
onDrop(event:DndDropEvent) {
console.log("dropped", JSON.stringify(event, null, 2));
}
}
app.module
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { DndModule } from 'ngx-drag-drop';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
DndModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
API
export type DropEffect = "move" | "copy" | "link" | "none";
export type EffectAllowed = DropEffect | "copyMove" | "copyLink" | "linkMove" | "all";
export type DndDragImageOffsetFunction = ( event:DragEvent, dragImage:Element ) => { x:number, y:number };
@Directive( {
selector: "[dndDraggable]"
} )
export declare class DndDraggableDirective {
dndDraggable: any;
dndEffectAllowed: EffectAllowed;
dndType?: string;
dndDisableIf: boolean;
dndDraggingClass: string = "dndDragging";
dndDraggingSourceClass: string = "dndDraggingSource";
dndDraggableDisabledClass = "dndDraggableDisabled";
dndDragImageOffsetFunction:DndDragImageOffsetFunction = calculateDragImageOffset;
readonly dndStart: EventEmitter<DragEvent>;
readonly dndEnd: EventEmitter<DragEvent>;
readonly dndMoved: EventEmitter<DragEvent>;
readonly dndCopied: EventEmitter<DragEvent>;
readonly dndLinked: EventEmitter<DragEvent>;
readonly dndCanceled: EventEmitter<DragEvent>;
}
export interface DndDropEvent {
event: DragEvent;
dropEffect: DropEffect;
isExternal:boolean;
data?: any;
index?: number;
}
@Directive( {
selector: "[dndDropzone]"
} )
export declare class DndDropzoneDirective {
dndDropzone?: string[];
dndEffectAllowed: EffectAllowed;
dndDisableIf: boolean;
dndAllowExternal: boolean;
dndHorizontal: boolean;
dndDragoverClass: string = "dndDragover";
dndDropzoneDisabledClass = "dndDropzoneDisabled";
readonly dndDragover: EventEmitter<DragEvent>;
readonly dndDrop: EventEmitter<DndDropEvent>;
}
Touch support
Install the mobile-drag-drop
module available on npm.
Add the following lines to your js code
import { polyfill } from 'mobile-drag-drop';
import { scrollBehaviourDragImageTranslateOverride } from "mobile-drag-drop/scroll-behaviour";
polyfill( {
dragImageTranslateOverride: scrollBehaviourDragImageTranslateOverride
} );
try {
window.addEventListener( "touchmove", function() { }, { passive: false } );
}
catch(e){}
For more info on the polyfill check it out on GitHub
https://github.com/timruffles/mobile-drag-drop
Why?
HTML Drag-And-Drop API implementations are not behaving the same way across browsers.
The directives contained in this module enable declarative drag and drop that "just works" across browsers in a consistent way.
Credits go to the author and contributors of angular-drag-drop-lists.
Maintenance
This project was generated with Angular CLI.
For the library build it uses ng-packagr.
Edit Library
- edit lib code
- run
npm start
(currently needs to be re-run on every lib code change)
Release Library
- assure correct version is set in
package.json
- build library with
npm run build:lib
- publish library with
npm run publish:stable
(use npm run publish:next
for pre-releases)
Release Docs
- build docs site with
npm run build:docs
- commit and push changes in
docs
to master