https://github.com/akserg/ng2-dnd
Angular 2 Drag-and-Drop without dependencies
https://github.com/akserg/ng2-dnd
angular angular2 angular4 drag drag-and-drop drop dropzone
Last synced: 6 months ago
JSON representation
Angular 2 Drag-and-Drop without dependencies
- Host: GitHub
- URL: https://github.com/akserg/ng2-dnd
- Owner: akserg
- License: mit
- Created: 2016-03-10T15:01:36.000Z (over 9 years ago)
- Default Branch: master
- Last Pushed: 2023-01-08T16:27:01.000Z (almost 3 years ago)
- Last Synced: 2025-05-07T23:44:44.877Z (6 months ago)
- Topics: angular, angular2, angular4, drag, drag-and-drop, drop, dropzone
- Language: TypeScript
- Size: 2.68 MB
- Stars: 837
- Watchers: 43
- Forks: 247
- Open Issues: 208
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
- awesome-angular-components - ng2-dnd - Angular 2 Drag-and-Drop without dependencies. (Uncategorized / Uncategorized)
- awesome-angular - ng2-dnd - Angular 2 Drag-and-Drop without dependencies. (Uncategorized / Uncategorized)
- awesome-angular-components - ng2-dnd - Angular 2 Drag-and-Drop without dependencies (Uncategorized / Uncategorized)
- awesome-angular-components - ng2-dnd - Angular 2 Drag-and-Drop without dependencies. (Uncategorized / Uncategorized)
README
# Angular 2 Drag-and-Drop [](https://badge.fury.io/js/ng2-dnd) [](https://www.npmjs.com/package/ng2-dnd)
Angular 2 Drag-and-Drop without dependencies.
Follow me [](https://twitter.com/akopkokhyants) to be notified about new releases.
[](https://travis-ci.org/akserg/ng2-dnd)
[](https://david-dm.org/akserg/ng2-dnd)
[](https://david-dm.org/akserg/ng2-dnd#info=devDependencies)
[](https://snyk.io/test/github/akserg/ng2-dnd)
_Some of these APIs and Components are not final and are subject to change!_
## Transpilation to Angular Package Format
The library uses [ng-packagr](https://github.com/dherges/ng-packagr) to transpile into the Angular Package Format:
- Bundles library in `FESM2015`, `FESM5`, and `UMD` formats
- The npm package can be consumed by `Angular CLI`, `Webpack`, or `SystemJS`
- Creates type definitions (`.d.ts`)
- Generates Ahead-of-Time metadata (`.metadata.json`)
- Auto-discovers and bundles secondary entry points such as `@my/foo`, `@my/foo/testing`, `@my/foo/bar`
## Installation
```bash
npm install ng2-dnd --save
```
## Demo
- Webpack demo available [here](https://angular-dxqjhj.stackblitz.io)
- SystemJS demo available [here](http://embed.plnkr.co/JbG8Si)
## Usage
If you use SystemJS to load your files, you might have to update your config:
```js
System.config({
map: {
'ng2-dnd': 'node_modules/ng2-dnd/bundles/ng2-dnd.umd.js'
}
});
```
#### 1. Add the default styles
- Import the `style.css` into your web page from `node_modules/ng2-dnd/bundles/style.css`
#### 2. Import the `DndModule`
Import `DndModule.forRoot()` in the NgModule of your application.
The `forRoot` method is a convention for modules that provide a singleton service.
```ts
import {BrowserModule} from "@angular/platform-browser";
import {NgModule} from '@angular/core';
import {DndModule} from 'ng2-dnd';
@NgModule({
imports: [
BrowserModule,
DndModule.forRoot()
],
bootstrap: [AppComponent]
})
export class AppModule {
}
```
If you have multiple NgModules and you use one as a shared NgModule (that you import in all of your other NgModules),
don't forget that you can use it to export the `DndModule` that you imported in order to avoid having to import it multiple times.
```ts
@NgModule({
imports: [
BrowserModule,
DndModule
],
exports: [BrowserModule, DndModule],
})
export class SharedModule {
}
```
#### 3. Use Drag-and-Drop operations with no code
```js
import {Component} from '@angular/core';
@Component({
selector: 'simple-dnd',
template: `
Simple Drag-and-Drop
Available to drag
Drag Me
Place to drop
Item was dropped here
`
})
export class SimpleDndComponent {
simpleDrop: any = null;
}
```
#### 4. Add handle to restrict draggable zone of component
```js
import {Component} from '@angular/core';
@Component({
selector: 'simple-dnd-handle',
template: `
Simple Drag-and-Drop with handle
Available to drag
=
Drag Handle
Place to drop
Item was dropped here
`
})
export class SimpleDndHandleComponent {
simpleDrop: any = null;
}
```
#### 5. Restriction Drag-and-Drop operations with drop zones
You can use property *dropZones* (actually an array) to specify in which place you would like to drop the draggable element:
```js
import {Component} from '@angular/core';
@Component({
selector: 'zone-dnd',
template: `
Restricted Drag-and-Drop with zones
Available to drag
Drag Me
Zone 1 only
Available to drag
Drag Me
Zone 1 & 2
Zone 1
Item was dropped here
Zone 2
Item was dropped here
`
})
export class ZoneDndComponent {
restrictedDrop1: any = null;
restrictedDrop2: any = null;
}
```
#### 6. Transfer custom data via Drag-and-Drop
You can transfer data from draggable to droppable component via *dragData* property of Draggable component:
```js
import {Component} from '@angular/core';
@Component({
selector: 'custom-data-dnd',
template: `
Transfer custom data in Drag-and-Drop
Available to drag
Drag Me
{{transferData | json}}
Place to drop (Items:{{receivedData.length}})
0" *ngFor="let data of receivedData">{{data | json}}
`
})
export class CustomDataDndComponent {
transferData: Object = {id: 1, msg: 'Hello'};
receivedData: Array = [];
transferDataSuccess($event: any) {
this.receivedData.push($event);
}
}
```
#### 7. Use a custom function to determine where dropping is allowed
For use-cases when a static set of `dropZone`s is not possible, a custom function can be used to dynamically determine whether an item can be dropped or not. To achieve that, set the `allowDrop` property to this boolean function.
In the following example, we have two containers that only accept numbers that are multiples of a user-input base integer. `dropZone`s are not helpful here because they are static, whereas the user input is dynamic.
```js
import { Component } from '@angular/core';
@Component({
selector: 'custom-function-dnd',
template: `
Use a custom function to determine where dropping is allowed
Available to drag
dragData = 6
dragData = 10
dragData = 30
allowDropFunction(baseInteger: any): any {{ '{' }}
return (dragData: any) => dragData % baseInteger === 0;
{{ '}' }}
Multiples of
only
dragData = {{item}}
Multiples of
only
dragData = {{item}}
`
})
export class CustomFunctionDndComponent {
box1Integer: number = 3;
box2Integer: number = 10;
box1Items: string[] = [];
box2Items: string[] = [];
allowDropFunction(baseInteger: number): any {
return (dragData: any) => dragData % baseInteger === 0;
}
addTobox1Items($event: any) {
this.box1Items.push($event.dragData);
}
addTobox2Items($event: any) {
this.box2Items.push($event.dragData);
}
}
```
#### 8. Shopping basket with Drag-and-Drop
Here is an example of shopping backet with products adding via drag and drop operation:
```js
import { Component } from '@angular/core';
@Component({
selector: 'shoping-basket-dnd',
template: `
Drag-and-Drop - Shopping basket
Available products
0" [dragData]="product" (onDragSuccess)="orderedProduct($event)" [dropZones]="['demo1']">
{{product.name}} - \${{product.cost}}
(available: {{product.quantity}})
0">{{product.name}}
(NOT available)
Shopping Basket
(to pay: \${{totalCost()}})
{{product.name}}
(ordered: {{product.quantity}}
cost: \${{product.cost * product.quantity}})
`
})
export class ShoppingBasketDndComponent {
availableProducts: Array = [];
shoppingBasket: Array = [];
constructor() {
this.availableProducts.push(new Product('Blue Shoes', 3, 35));
this.availableProducts.push(new Product('Good Jacket', 1, 90));
this.availableProducts.push(new Product('Red Shirt', 5, 12));
this.availableProducts.push(new Product('Blue Jeans', 4, 60));
}
orderedProduct($event: any) {
let orderedProduct: Product = $event.dragData;
orderedProduct.quantity--;
}
addToBasket($event: any) {
let newProduct: Product = $event.dragData;
for (let indx in this.shoppingBasket) {
let product: Product = this.shoppingBasket[indx];
if (product.name === newProduct.name) {
product.quantity++;
return;
}
}
this.shoppingBasket.push(new Product(newProduct.name, 1, newProduct.cost));
this.shoppingBasket.sort((a: Product, b: Product) => {
return a.name.localeCompare(b.name);
});
}
totalCost(): number {
let cost: number = 0;
for (let indx in this.shoppingBasket) {
let product: Product = this.shoppingBasket[indx];
cost += (product.cost * product.quantity);
}
return cost;
}
}
class Product {
constructor(public name: string, public quantity: number, public cost: number) {}
}
```
#### 9. Simple sortable with Drag-and-Drop
Here is an example of simple sortable of favorite drinks moving in container via drag and drop operation:
```js
import {Component} from '@angular/core';
@Component({
selector: 'simple-sortable',
template: `
Simple sortable
Favorite drinks
- {{item}}
My prefences:
{{i + 1}}) {{item}}
`
})
export class SimpleSortableComponent {
listOne: Array = ['Coffee', 'Orange Juice', 'Red Wine', 'Unhealty drink!', 'Water'];
}
```
#### 10. Simple sortable with Drag-and-Drop handle
Add handle to restict grip zone of sortable component.
```js
import {Component} from '@angular/core';
@Component({
selector: 'simple-sortable-handle',
template: `
Simple sortable handle
Favorite drinks
-
=
{{item}}
My prefences:
{{i + 1}}) {{item}}
`
})
export class SimpleSortableHandleComponent {
listOne: Array = ['Coffee', 'Orange Juice', 'Red Wine', 'Unhealty drink!', 'Water'];
}
```
#### 11. Simple sortable With Drop into recycle bin
Here is an example of multi list sortable of boxers moving in container and between containers via drag and drop operation:
```js
import {Component} from '@angular/core';
@Component({
selector: 'recycle-multi-sortable',
template: `
Simple sortable With Drop into recycle bin
Favorite drinks
- {{item}}
Recycle bin: Drag into me to delete it
Recycled: {{listRecycled.toString()}}
`
})
export class RecycleMultiSortableComponent {
listOne: Array = ['Coffee', 'Orange Juice', 'Red Wine', 'Unhealty drink!', 'Water'];
listRecycled: Array = [];
}
```
#### 12. Simple sortable With Drop into something, without delete it
Here is an example of simple sortable list of items copying in target container:
```js
import {Component} from '@angular/core';
@Component({
selector: 'simple-sortable-copy',
template: `
Simple sortable With Drop into something, without delete it
Source List
- {{source.name}}
Target List
-
{{target.name}}
`
})
export class SimpleSortableCopyComponent {
sourceList: Widget[] = [
new Widget('1'), new Widget('2'),
new Widget('3'), new Widget('4'),
new Widget('5'), new Widget('6')
];
targetList: Widget[] = [];
addTo($event: any) {
this.targetList.push($event.dragData);
}
}
class Widget {
constructor(public name: string) {}
}
```
#### 13. Multi list sortable between containers
Here is an example of multi list sortable of boxers moving in container and between containers via drag and drop operation:
```js
import {Component} from '@angular/core';
@Component({
selector: 'embedded-sortable',
template: `
Move items between multi list sortable containers
Drag Containers
{{container.id}} - {{container.name}}
- {{widget.name}}
Widgets
{{widget.name}}
`
})
export class EmbeddedSortableComponent {
dragOperation: boolean = false;
containers: Array = [
new Container(1, 'Container 1', [new Widget('1'), new Widget('2')]),
new Container(2, 'Container 2', [new Widget('3'), new Widget('4')]),
new Container(3, 'Container 3', [new Widget('5'), new Widget('6')])
];
widgets: Array = [];
addTo($event: any) {
if ($event) {
this.widgets.push($event.dragData);
}
}
}
class Container {
constructor(public id: number, public name: string, public widgets: Array) {}
}
class Widget {
constructor(public name: string) {}
}
```
#### 14. Simple FormArray sortable with Drag-and-Drop
Here is an example of simple sortable of favorite drinks moving in container via drag and drop operation but using FormArray instead of Array:
```js
import {Component} from '@angular/core';
import {FormArray, FormControl} from '@angular/forms';
@Component({
selector: 'simple-formarray-sortable',
template: `
Simple FormArray sortable
Favorite drinks
-
My prefences:
{{i + 1}}) {{item.value}}
`
})
export class SimpleFormArraySortableComponent {
listOne: FormArray = new FormArray([
new FormControl('Coffee'),
new FormControl('Orange Juice'),
new FormControl('Red Wine'),
new FormControl('Unhealty drink!'),
new FormControl('Water')
]);
}
```
## How to pass multiple data in dragData while dragging ?
1) As an array:
``` html
[dragData]="[aComponent,'component-in-bar']"
```
``` javascript
loadComponent($event){
console.log($event.dragData[0]); // aComponent
console.log($event.dragData[1]); // 'component-in-bar' OR 'component-in-designer'
}
```
2) As an object:
``` html
[dragData]="{component: aComponent, location: 'component-in-bar'}"
```
``` javascript
loadComponent($event){
console.log($event.dragData.component); // aComponent
console.log($event.dragData.location); // 'component-in-bar' OR 'component-in-designer'
}
```
# Retreiving files in a drop zone
Since it is possible to drag and drop one or more files to a drop zone, you need to handle the incoming files.
```js
import {Component} from '@angular/core';
import {Http, Headers} from '@angular/http';
import {DND_PROVIDERS, DND_DIRECTIVES} from 'ng2-dnd/ng2-dnd';
import {bootstrap} from '@angular/platform-browser-dynamic';
bootstrap(AppComponent, [
DND_PROVIDERS // It is required to have 1 unique instance of your service
]);
@Component({
selector: 'app',
directives: [DND_DIRECTIVES],
template: `
Simple Drag-and-Drop
>
Place to drop
`
})
export class AppComponent {
constructor(private _http: Http) { }
/**
* The $event is a structure:
* {
* dragData: any,
* mouseEvent: MouseEvent
* }
*/
transferDataSuccess($event) {
// let attachmentUploadUrl = 'assets/data/offerspec/offerspec.json';
// loading the FileList from the dataTransfer
let dataTransfer: DataTransfer = $event.mouseEvent.dataTransfer;
if (dataTransfer && dataTransfer.files) {
// needed to support posting binaries and usual form values
let headers = new Headers();
headers.append('Content-Type', 'multipart/form-data');
let files: FileList = dataTransfer.files;
// uploading the files one by one asynchrounusly
for (let i = 0; i < files.length; i++) {
let file: File = files[i];
// just for debugging
console.log('Name: ' + file.name + '\n Type: ' + file.type + '\n Size: ' + file.size + '\n Date: ' + file.lastModifiedDate);
// collecting the data to post
var data = new FormData();
data.append('file', file);
data.append('fileName', file.name);
data.append('fileSize', file.size);
data.append('fileType', file.type);
data.append('fileLastMod', file.lastModifiedDate);
// posting the data
this._http
.post(attachmentUploadUrl, data, {
headers: headers
})
.toPromise()
.catch(reason => {
console.log(JSON.stringify(reason));
});
}
}
}
}
# Credits
- [Francesco Cina](https://github.com/ufoscout)
- [Valerii Kuznetsov](https://github.com/solival)
- [Shane Oborn](https://github.com/obosha)
- [Juergen Gutsch](https://github.com/JuergenGutsch)
- [Damjan Cilenšek](https://github.com/loudandwicked)
# License
[MIT](/LICENSE)