Security News
Input Validation Vulnerabilities Dominate MITRE's 2024 CWE Top 25 List
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Angular 2 Drag-and-Drop without dependencies.
Follow me to be notified about new releases.
npm install ng2-dnd --save
Simple examples using ng2-dnd:
Online demo available here
Plunker demo available here
If you use SystemJS to load your files, you might have to update your config with this if you don't use defaultJSExtensions: true
:
System.config({
packages: {
"/ng2-dnd": {"defaultExtension": "js"}
}
});
Finally, you can use ng2-dnd in your Angular 2 project:
DND_PROVIDERS, DND_DIRECTIVES
from ng2-dnd/ng2-dnd
;DND_PROVIDERS
in the bootstrap of your application;DND_DIRECTIVES
to the directives
property of your application component;dnd-draggable
and dnd-droppable
properties in template of your components.import {Component} from '@angular/core';
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: `
<h4>Simple Drag-and-Drop</h4>
<div class="row">
<div class="col-sm-3">
<div class="panel panel-success">
<div class="panel-heading">Available to drag</div>
<div class="panel-body">
<div class="panel panel-default" dnd-draggable [dragEnabled]="true">
<div class="panel-body">
<div>Drag Me</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-3">
<div dnd-droppable class="panel panel-info">
<div class="panel-heading">Place to drop</div>
<div class="panel-body">
</div>
</div>
</div>
<div class="col-sm-3">
<div dnd-droppable class="panel panel-warning">
<div class="panel-heading">Restricted to drop</div>
<div class="panel-body">
</div>
</div>
</div>
</div>
`
})
export class AppComponent {
constructor() { }
}
You can use property dropZones (actually an array) to specify in which place you would like to drop the draggable element:
import {Component} from '@angular/core';
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: `
<h4>Restricting Drag-and-Drop with zones</h4>
<div class="row">
<div class="col-sm-3">
<div class="panel panel-primary">
<div class="panel-heading">Available to drag</div>
<div class="panel-body">
<div class="panel panel-default" dnd-draggable [dragEnabled]="true"
[dropZones]="['zone1']">
<div class="panel-body">
<div>Drag Me</div>
<div>Zone 1 only</div>
</div>
</div>
</div>
</div>
<div class="panel panel-success">
<div class="panel-heading">Available to drag</div>
<div class="panel-body">
<div class="panel panel-default" dnd-draggable [dragEnabled]="true"
[dropZones]="['zone1', 'zone2']">
<div class="panel-body">
<div>Drag Me</div>
<div>Zone 1 & 2</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-3">
<div dnd-droppable class="panel panel-info" [dropZones]="['zone1']">
<div class="panel-heading">Zone 1</div>
<div class="panel-body">
</div>
</div>
</div>
<div class="col-sm-3">
<div dnd-droppable class="panel panel-warning" [dropZones]="['zone2']">
<div class="panel-heading">Zone 2</div>
<div class="panel-body">
</div>
</div>
</div>
</div>
`
})
export class AppComponent {
constructor() { }
}
You can transfer data from draggable to droppable component via dragData property of Draggable component:
import {Component} from '@angular/core';
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: `
<h4>Transfer custom data in Drag-and-Drop</h4>
<div class="row">
<div class="col-sm-3">
<div class="panel panel-success">
<div class="panel-heading">Available to drag</div>
<div class="panel-body">
<div class="panel panel-default" dnd-draggable [dragEnabled]="true"
[dragData]="transferData">
<div class="panel-body">
<div>Drag Me</div>
<div>{{transferData | json}}</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-3">
<div dnd-droppable class="panel panel-info"
(onDropSuccess)="transferDataSuccess($event)">
<div class="panel-heading">Place to drop (Items:{{receivedData.length}})</div>
<div class="panel-body">
<div [hidden]="!receivedData.length > 0"
*ngFor="#data of receivedData">{{data | json}}</div>
</div>
</div>
</div>
</div>
`
})
export class AppComponent {
transferData:Object = {id:1, msg: 'Hello'};
receivedData:Array<any> = [];
constructor() { }
/**
* The $event is a structure:
* {
* dragData: any,
* mouseEvent: MouseEvent
* }
*/
transferDataSuccess($event) {
this.receivedData.push($event.dragData);
}
}
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.
import {Component} from '@angular/core';
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: `
<h4>Use a custom function to determine where dropping is allowed</h4>
<div class="row">
<div class="col-sm-3">
<div class="panel panel-success">
<div class="panel-heading">Available to drag</div>
<div class="panel-body">
<div class="panel panel-default" dnd-draggable [dragData]="6">
<div class="panel-body">dragData = 6</div>
</div>
<div class="panel panel-default" dnd-draggable [dragData]="10">
<div class="panel-body">dragData = 10</div>
</div>
<div class="panel panel-default" dnd-draggable [dragData]="30">
<div class="panel-body">dragData = 30</div>
</div>
</div>
</div>
</div>
<div class="col-sm-6">
<pre>allowDropFunction(baseInteger) {
return (dragData) => dragData % baseInteger === 0;
}</pre>
<div class="row">
<div class="col-sm-6">
<div dnd-droppable class="panel panel-info" [allowDrop]="allowDropFunction(box1Integer)">
<div class="panel-heading">
Multiples of
<input type="number" [(ngModel)]="box1Integer" style="width: 4em">
only
</div>
<div class="panel-body">
<div>
</div>
</div>
</div>
</div>
<div class="col-sm-6">
<div dnd-droppable class="panel panel-warning" [allowDrop]="allowDropFunction(box2Integer)">
<div class="panel-heading">
Multiples of
<input type="number" [(ngModel)]="box2Integer" style="width: 4em">
only
</div>
<div class="panel-body">
<div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`
})
export class AppComponent {
box1Integer: number = 3;
box2Integer: number = 10;
allowDropFunction(baseInteger): boolean {
return (dragData) => dragData % baseInteger === 0;
}
}
Here is an example of shopping backet with products adding via drag and drop operation:
import {Component} from '@angular/core';
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: `
<h4>Shopping basket</h4>
<div class="row">
<div class="col-sm-3">
<div class="panel panel-success">
<div class="panel-heading">Available products</div>
<div class="panel-body">
<div *ngFor="#product of availableProducts" class="panel panel-default"
dnd-draggable [dragEnabled]="product.quantity>0" [dragData]="product"
(onDragSuccess)="orderedProduct($event)" [dropZones]="['demo1']">
<div class="panel-body">
<div [hidden]="product.quantity===0">{{product.name}} - \${{product.cost}}
<br>(available: {{product.quantity}})</div>
<div [hidden]="product.quantity>0"><del>{{product.name}}</del>
<br>(NOT available)</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-3">
<div dnd-droppable (onDropSuccess)="addToBasket($event)" [dropZones]="['demo1']"
class="panel panel-info">
<div class="panel-heading">Shopping Basket<br>(to pay: \${{totalCost()}})</div>
<div class="panel-body">
<div *ngFor="#product of shoppingBasket" class="panel panel-default">
<div class="panel-body">
{{product.name}}<br>(ordered: {{product.quantity}}
<br>cost: \${{product.cost * product.quantity}})
</div>
</div>
</div>
</div>
</div>
</div>
`
})
export class AppComponent {
availableProducts: Array<Product> = [];
shoppingBasket: Array<Product> = [];
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(orderedProduct: Product) {
orderedProduct.quantity--;
}
/**
* The $event is a structure:
* {
* dragData: any,
* mouseEvent: MouseEvent
* }
*/
addToBasket($event) {
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));
}
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;
}
}
Here is an example of simple sortable of favorite drinks moving in container via drag and drop operation:
import {Component} from '@angular/core';
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: `
<h4>Simple sortable</h4>
<div class="row">
<div class="col-sm-3">
<div class="panel panel-success">
<div class="panel-heading">
Favorite drinks
</div>
<div class="panel-body">
<ul class="list-group" dnd-sortable-container [sortableData]="listOne">
<li *ngFor="#item of listOne; #i = index" class="list-group-item" dnd-sortable [sortableIndex]="i">{{item}}</li>
</ul>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-body">
My prefences:<br/>
<span *ngFor="#item of listOne; #i = index">{{i + 1}}) {{item}}<br/></span>
</div>
</div>
</div>
</div>`
})
export class AppComponent {
listOne:Array<string> = ['Coffee','Orange Juice','Red Wine','Unhealty drink!','Water'];
}
Here is an example of multi list sortable of boxers moving in container and between containers via drag and drop operation:
import {Component} from '@angular/core';
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: `
<h4>Multi list sortable</h4>
<div class="row">
<div class="col-sm-3">
<div class="panel panel-warning">
<div class="panel-heading">
Available boxers
</div>
<div class="panel-body" dnd-sortable-container [dropZones]="['boxers-zone']" [sortableData]="listBoxers">
<ul class="list-group" >
<li *ngFor="#item of listBoxers; #i = index" class="list-group-item" dnd-sortable [sortableIndex]="i">{{item}}</li>
</ul>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="panel panel-success">
<div class="panel-heading">
First Team
</div>
<div class="panel-body" dnd-sortable-container [dropZones]="['boxers-zone']" [sortableData]="listTeamOne">
<ul class="list-group" >
<li *ngFor="#item of listTeamOne; #i = index" class="list-group-item" dnd-sortable [sortableIndex]="i">{{item}}</li>
</ul>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="panel panel-info">
<div class="panel-heading">
Second Team
</div>
<div class="panel-body" dnd-sortable-container [dropZones]="['boxers-zone']" [sortableData]="listTeamTwo">
<ul class="list-group">
<li *ngFor="#item of listTeamTwo; #i = index" class="list-group-item" dnd-sortable [sortableIndex]="i">{{item}}</li>
</ul>
</div>
</div>
</div>
</div>`
})
export class AppComponent {
listBoxers:Array<string> = ['Sugar Ray Robinson','Muhammad Ali','George Foreman','Joe Frazier','Jake LaMotta','Joe Louis','Jack Dempsey','Rocky Marciano','Mike Tyson','Oscar De La Hoya'];
listTeamOne:Array<string> = [];
listTeamTwo:Array<string> = [];
}
FAQs
Angular 2 Drag-and-Drop without dependencies
The npm package ng2-dnd receives a total of 3,231 weekly downloads. As such, ng2-dnd popularity was classified as popular.
We found that ng2-dnd demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.