<!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;
    })
  }
}