<!DOCTYPE html>
<html>
<head>
<title>angular2 playground</title>
<link data-require="bootstrap-css@3.3.6" data-semver="3.3.6" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" />
<link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/2.0.0-beta.17/angular2-polyfills.js"></script>
<script src="https://code.angularjs.org/tools/system.js"></script>
<script src="https://code.angularjs.org/tools/typescript.js"></script>
<script src="config.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</head>
<body>
<my-app>
loading...
</my-app>
</body>
</html>
/* Styles go here */
li {
list-style: none;
border: 1px solid #DDD;
width: 300px;
border-radius: 5px;
padding: 5px 20px;
background-color: ghostwhite;
margin: 5px;
cursor: move;
}
.drag-src {
opacity: 0.4;
}
h1 {
margin-left: 50px;
color:#444;
}
### Angular2 Drag n Drop
A simple plunker demonstrating dragNdrop in Angular2:
- Uses SystemJS + TypeScript to compile on the fly
- Includes binding, directives, http, pipes, and DI usage.
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
//map tells the System loader where to look for things
map: {
app: "./src",
'@angular': 'https://npmcdn.com/@angular',
'rxjs': 'https://npmcdn.com/rxjs@5.0.0-beta.6'
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
'@angular/core': {
main: 'core.umd.js',
defaultExtension: 'js'
},
'@angular/compiler': {
main: 'compiler.umd.js',
defaultExtension: 'js'
},
'@angular/common': {
main: 'common.umd.js',
defaultExtension: 'js'
},
'@angular/platform-browser-dynamic': {
main: 'platform-browser-dynamic.umd.js',
defaultExtension: 'js'
},
'@angular/platform-browser': {
main: 'platform-browser.umd.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
}
}
});
//main entry point
import {bootstrap} from '@angular/platform-browser-dynamic';
import {App} from './app';
bootstrap(App, [])
.catch(err => console.error(err));
//our root app component
import {Component} from '@angular/core'
import { TodoListComponent } from './todo-list/index';
@Component({
selector: 'my-app',
providers: [],
template: `
<h1>
To-dle-do
</h1>
<todo-list></todo-list>
`,
directives: [TodoListComponent]
})
export class App {
constructor() {
title = 'To-dle-do';
}
}
export { TodoListComponent } from './todo-list.component';
import { Component, OnInit } from '@angular/core';
import { TodoService} from './todo-list.service';
import { TodoComponent, Todo } from '../todo/index';
import { MakeDraggable, MakeDroppable } from '../shared/index';
@Component({
selector: 'todo-list',
template: `
<ul>
<todo *ngFor="let todo of todos" [todo]="todo" [makeDraggable]="todo" makeDroppable (dropped)="onDrop($event, todo)"></todo>
</ul>
`,
providers: [TodoService],
directives: [TodoComponent, MakeDraggable, MakeDroppable]
})
export class TodoListComponent implements OnInit {
todos:Todo[];
constructor(private _todoSvc: TodoService) {}
ngOnInit() {
this.todos = this._todoSvc.getTodos();
}
onDrop(src: Todo, trg: Todo) {
this._moveRow(src.order, trg.order);
}
_moveRow(src, trg) {
src = parseInt(src);
trg = parseInt(trg);
// If the element was moved down
if (src > trg) {
for (let i = trg; i < src; i++) {
this.todos[i].order++;
}
} else { // if the element was moved up
for (let i = src + 1; i <= trg; i++) {
this.todos[i].order--;
}
}
this.todos[src].order = trg;
this.todos.sort((a, b) => a.order - b.order);
}
}
export { TodoComponent } from './todo.component';
import { Component, OnInit, Input, ElementRef } from '@angular/core';
import { TodoService} from './todo-list.service';
@Component({
selector: 'todo',
template: `
<li>
<span>{{todo.description}}</span>
<input type="checkbox" [checked]="todo.done" class="pull-right">
</li>
`,
})
export class TodoComponent implements OnInit {
@Input() todo:Todo;
constructor() {}
ngOnInit() {}
}
export interface Todo {
order: number;
description: string;
done?: boolean;
}
import { Injectable } from '@angular/core';
import { Todo } from '../todo/index';
@Injectable()
export class TodoService {
getTodos(): Todo[] {
return [
{order: 0, description: 'Clean up code'},
{order: 1, description: 'Blog about it'},
{order: 2, description: 'Push code to Github'},
{order: 3, description: 'Share blog on twitter'},
];
}
}
export * from './make-draggable.directive';
export * from './make-droppable.directive';
import { Directive , Input, ElementRef} from '@angular/core';
@Directive({
selector: '[makeDraggable]'
})
export class MakeDraggable {
@Input('makeDraggable') data: any;
constructor(private _elementRef: ElementRef) {}
ngOnInit() {
// Get the current element
let el = this._elementRef.nativeElement.querySelector('li');
// Set the draggable attribute to the element
el.draggable = 'true';
// Set up the dragstart event and add the drag-src CSS class
// to change the visual appearance. Set the current todo as the data
// payload by stringifying the object first
el.addEventListener('dragstart', (e) => {
console.log('Start');
el.classList.add('drag-src')
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text', JSON.stringify(this.data));
});
// Remove the drag-src class
el.addEventListener('dragend', (e) => {
e.preventDefault();
el.classList.remove('drag-src')
});
}
}
import { Directive, OnInit, ElementRef, Output, EventEmitter } from '@angular/core';
@Directive({
selector: '[makeDroppable]'
})
export class MakeDroppable implements OnInit {
@Output() dropped: EventEmitter<any> = new EventEmitter();
constructor(private _elementRef: ElementRef) {}
ngOnInit() {
let el = this._elementRef.nativeElement;
// Add a style to indicate that this element is a drop target
el.addEventListener('dragenter', (e) => {
el.classList.add('over');
});
// Remove the style
el.addEventListener('dragleave', (e) => {
el.classList.remove('over');
});
el.addEventListener('dragover', (e) => {
if (e.preventDefault) {
e.preventDefault();
}
e.dataTransfer.dropEffect = 'move';
return false;
});
// On drop, get the data and convert it back to a JSON object
// and fire off an event passing the data
el.addEventListener('drop', (e) => {
if (e.stopPropagation) {
e.stopPropagation(); // Stops some browsers from redirecting.
}
el.classList.remove('over');
let data = JSON.parse(e.dataTransfer.getData('text'));
this.dropped.emit(data);
return false;
})
}
}