<!DOCTYPE html>
<html>

  <head>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <script type="text/javascript" charset="utf-8">
      window.AngularVersionForThisPlunker = 'latest'
    </script>
    <title>angular4-drag-drop demo</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" >
    <!-- Polyfills -->
    <script src="https://unpkg.com/core-js/client/shim.min.js"></script>

    <script src="https://unpkg.com/zone.js@0.7.4?main=browser"></script>
    <script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>

    <script src="systemjs.config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
  </head>
  <body>
    <app-root>Loading AppComponent content here ...</app-root>
  </body>

</html>
/* Styles go here */

### Angular4 Drag Demo

Demo using the angular4-drag-drop

https://www.npmjs.com/package/angular4-drag-drop
/**
 * WEB ANGULAR VERSION
 * (based on systemjs.config.js in angular.io)
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    // DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
    transpiler: 'ts',
    typescriptOptions: {
      // Copy of compiler options in standard tsconfig.json
      "target": "es5",
      "module": "commonjs",
      "moduleResolution": "node",
      "sourceMap": true,
      "emitDecoratorMetadata": true,
      "experimentalDecorators": true,
      "lib": ["es2015", "dom"],
      "noImplicitAny": true,
      "suppressImplicitAnyIndexErrors": true
    },
    meta: {
      'typescript': {
        "exports": "ts"
      }
    },
    paths: {
      // paths serve as alias
      'npm:': 'https://unpkg.com/'
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      'app': 'app',

      // angular bundles
      '@angular/animations': 'npm:@angular/animations/bundles/animations.umd.js',
      '@angular/animations/browser': 'npm:@angular/animations/bundles/animations-browser.umd.js',
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser/animations': 'npm:@angular/platform-browser/bundles/platform-browser-animations.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
      '@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
      '@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js',
      '@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js',

      // other libraries
      'rxjs':                      'npm:rxjs@5.0.1',
      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
      'ts':                        'npm:plugin-typescript@5.2.7/lib/plugin.js',
      'typescript':                'npm:typescript@2.3.2/lib/typescript.js',
      'angular4-drag-drop': 'https://unpkg.com/angular4-drag-drop@1.0.0'
    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        main: './main.ts',
        defaultExtension: 'ts',
        meta: {
          './*.ts': {
            loader: 'systemjs-angular-loader.js'
          }
        }
      },
      rxjs: {
        defaultExtension: 'js'
      },
      'angular4-drag-drop': {
        main: 'angular4-drag-drop.js',
        defaultExtension: 'js'
      }
    }
  });

})(this);
//main entry point
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app';

platformBrowserDynamic().bootstrapModule(AppModule)
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { DragDropDirectiveModule} from "angular4-drag-drop";
import { AppComponent } from './app.component';
import { DropAreaComponent } from './drop-area/drop-area.component';
import { NavigationComponent } from './navigation/navigation.component';
import { GenericBoxModule } from './generic-box/generic-box.module';
import { TypeCheckModule } from './type-check/type-check.module';

@NgModule({
  imports: [
    BrowserModule,
    GenericBoxModule,
    DragDropDirectiveModule,
    TypeCheckModule
  ],
  declarations: [
    AppComponent,
    DropAreaComponent,
    NavigationComponent
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-navigation',
  template:`
    <div *ngFor="let item of itemsToDrop" [dragDirective]='item' [dragHightlight]="'highlight'" (releaseDrop)="releaseDrop($event)" class="dragItem" >
      <app-generic-box [genericBox]='item'></app-generic-box>
    </div>
  `,
  styleUrls: ['./navigation.component.css']
})
export class NavigationComponent implements OnInit {
	private itemsToDrop:Array<Object> = [
		{
			name: 'Item to drop 1',
			content: 'desctiption 1'
		},
		{
			name: 'Item to drop 2',
			content: 'desctiption 2'
		},
		{
			name: 'Item to drop 3',
			content: 'desctiption 3'
		},
	]
  constructor() { }

  ngOnInit() {
  }
  private releaseDrop(event){
  	let index = this.itemsToDrop.indexOf(event);
  	if (index >= 0){
  		this.itemsToDrop.splice(index,1);
  	}
  }

}
import { Component} from '@angular/core';

@Component({
  selector: 'app-drop-area',
  template:`
    <p>
      drop-area works!
    </p>
    <div dropDirective (dropEvent)="addDropItem($event)" class="droppable" [dropHighlight]="'highlight'" >
    	<app-generic-box *ngFor="let item of itemsDropped" [genericBox]='item' class="dropItem"></app-generic-box>
    </div>
  `,
  styleUrls: ['./drop-area.component.css']
})
export class DropAreaComponent{
	private itemsDropped:Array<any> = [];
  constructor() { }

  private addDropItem(event){
  	this.itemsDropped.push(event);
  }
}
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { GenericBoxComponent } from './generic-box.component';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [
    GenericBoxComponent
  ],
  exports: [GenericBoxComponent]
})
export class GenericBoxModule { }
import { Component, OnInit,Input } from '@angular/core';

@Component({
  selector: 'app-generic-box',
  template: `
  <div class="genericBox">
  	{{genericBox.name}}
  	<p>{{genericBox.content}}</p>
  </div>
  `
})
export class GenericBoxComponent implements OnInit {
	@Input()
	genericBox:Object;
  constructor() { }

  ngOnInit() {
  	if (!this.genericBox){
  		this.genericBox = {name:'Generic Box 1', content:'Generic Box 1 Content'}
  	}
  }
}
var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm;
var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g;
var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g;

module.exports.translate = function(load){
  if (load.source.indexOf('moduleId') != -1) return load;

  var url = document.createElement('a');
  url.href = load.address;

  var basePathParts = url.pathname.split('/');

  basePathParts.pop();
  var basePath = basePathParts.join('/');

  var baseHref = document.createElement('a');
  baseHref.href = this.baseURL;
  baseHref = baseHref.pathname;

  if (!baseHref.startsWith('/base/')) { // it is not karma
    basePath = basePath.replace(baseHref, '');
  }

  load.source = load.source
    .replace(templateUrlRegex, function(match, quote, url){
      var resolvedUrl = url;

      if (url.startsWith('.')) {
        resolvedUrl = basePath + url.substr(1);
      }

      return 'templateUrl: "' + resolvedUrl + '"';
    })
    .replace(stylesRegex, function(match, relativeUrls) {
      var urls = [];

      while ((match = stringRegex.exec(relativeUrls)) !== null) {
        if (match[2].startsWith('.')) {
          urls.push('"' + basePath + match[2].substr(1) + '"');
        } else {
          urls.push('"' + match[2] + '"');
        }
      }

      return "styleUrls: [" + urls.join(', ') + "]";
    });

  return load;
};
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div class="col-xs-12">
      <div class="row">
        <h1>
          {{title}}
        </h1>
      </div>
      <div class="row">
        <h2>Very Basic</h2>
        <div class="col-md-4">
          <h3>Box from which to drag</h3>
          <app-navigation></app-navigation>
        </div>
        <div class="col-md-8">
          <h3>Box to drag things into</h3>
          <app-drop-area></app-drop-area>
        </div>
      </div>
      <app-type-check></app-type-check>
    </div>
  `
  ,
  styles: ['.main{padding:10px;}']
})
export class AppComponent {
  title = 'Draggable Boxes for Angular';
}
.dragItem{
  border:1px solid #aaa;
  width:50%;
  padding:2px 4px;
  margin:5px 0;
}
.highlight{
  border:solid 1px #0d0;
}
.droppable{
	padding:10px;
  border:1px solid #bbb;
  min-height:60px;
}
.highlight{
	border:solid 1px #0d0;
}
.dropItem{
  display:inline-block;
  padding:2px 4px;
  margin:4px;
  border:1px solid #aaa;
  background-color:#aaf;
}
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { GenericBoxModule } from '../generic-box/generic-box.module';
import { DragDropDirectiveModule} from "angular4-drag-drop";
import { TypeCheckComponent } from './type-check.component';
import { DropAreaTypeCheckComponent} from './drop-area-type-check/drop-area-type-check.component';
import { NavigationTypeCheckComponent } from './navigation-type-check/navigation-type-check.component';

@NgModule({
  imports: [
    CommonModule,
    GenericBoxModule,
    DragDropDirectiveModule
  ],
  declarations: [
    DropAreaTypeCheckComponent,
    NavigationTypeCheckComponent,
    TypeCheckComponent
  ],
  exports: [TypeCheckComponent]
})
export class TypeCheckModule { }
import { Component } from '@angular/core';
import { TypeCheckEnum } from './type-check-enum';

@Component({
  selector: 'app-type-check',
  template: `
    <div class="row">
      <h2>{{Title}}</h2>
      <div class="col-md-4">
        <app-navigation-type-check [dropItemType]='dropItemType'></app-navigation-type-check>
      </div>
      <div class="col-md-8">
        <app-drop-area-type-check (droppedItemType)="dropItemTypeCheck($event)"></app-drop-area-type-check>
      </div>
    </div>
  `
})
export class TypeCheckComponent {
  private title:String = 'Draggable Items that check to see if they are allowed to drop in drop areas';
  private dropItemType:any;
  private dropItemTypeCheck(event){
    this.dropItemType = event;
  }
}
export class EmptyEnumClass{}
export enum TypeCheckEnum{
  Round,
  Square
}
import { Component, Output, EventEmitter } from '@angular/core';
import {EmptyEnumClass, TypeCheckEnum} from '../type-check-enum';

@Component({
  selector: 'app-drop-area-type-check',
  template: `
    <p>
      Match Shapes<br />
      {{warningMessage}}
    </p>
    <div dropDirective (dropEvent)="addDropItem($event,typeCheck.Round)" (dragenterEvent)="dragEnter($event,typeCheck.Round)" (dragleaveEvent)="dragLeave()" class="droppable round-hole" [ngClass]="highlight[typeCheck.Round]">
    	<app-generic-box *ngFor="let item of itemsDroppedRound" [genericBox]='item'></app-generic-box>
    </div>
    <div dropDirective (dropEvent)="addDropItem($event,typeCheck.Square)" (dragenterEvent)="dragEnter($event,typeCheck.Square)" (dragleaveEvent)="dragLeave()" class="droppable square-hole" [ngClass]="highlight[typeCheck.Square]" >
      <app-generic-box *ngFor="let item of itemsDroppedSquare" [genericBox]='item'></app-generic-box>
    </div>
  `,
  styleUrls: ['./drop-area-type-check.component.css']
})
export class DropAreaTypeCheckComponent{
	private itemsDroppedRound:Array<any> = [];
  private itemsDroppedSquare:Array<any> = [];
  private warningMessage:string = '';
  private highlight:Array<string> = ['',''];
  private typeCheck = TypeCheckEnum;
  @Output()
  droppedItemType:EventEmitter<any> = new EventEmitter();

  constructor() { }
  
  private addDropItem(event,type){
    if (type === TypeCheckEnum.Square){
      if (event.type === TypeCheckEnum.Square){
        this.itemsDroppedSquare.push(event);
        this.droppedItemType.emit(event.type);
        this.warningMessage = '';
      }else{
        this.warningMessage = "Technically a round shape will fit in a square shape, try to match them"
      }
    }
    if (type === TypeCheckEnum.Round){
      if (event.type === TypeCheckEnum.Round){
        this.itemsDroppedRound.push(event);
        this.droppedItemType.emit(event.type);
        this.warningMessage = '';
      }else {
        this.warningMessage ="A square shape will not fit in a round shape."
      }
    }
  }

  private dragEnter(event,type){
    if (event.type !== type){
      this.highlight[type] = 'badHighlight';
    } else {
      this.highlight[type] = 'highlight';
    }
  }
  private dragLeave(){
    this.highlight=['',''];
  }
}
.droppable{
	padding:10px;
  border:solid 1px #aaa;
  height:100px;
  width:100px;
  display:inline-block;
  margin:0 10px;
}
.highlight{
	border:solid 1px #0f0;
}
.badHighlight{
  border:solid 1px #f00;
}
.round-hole{
  border-radius:50px;
}
import { Component, OnInit, Input } from '@angular/core';
import {EmptyEnumClass, TypeCheckEnum} from '../type-check-enum';

@Component({
  selector: 'app-navigation-type-check',
  template: `
    navigation works!
    <div *ngFor="let item of itemsToDrop" [dragDirective]='item' [dragHightlight]="'highlight'" (releaseDrop)="releaseDrop($event)" class="dragItem" [ngClass]="{'dragItem-round':item.type===0,'dragItem-square':item.type===1}" (startDrag)="startDrag(item)">
    	<app-generic-box [genericBox]='item'></app-generic-box>
    </div>
  `,
  styleUrls: ['./navigation-type-check.component.css']
})
export class NavigationTypeCheckComponent {
  @Input()
  dropItemType:any;
  private pegType = TypeCheckEnum;
	private itemsToDrop:Array<Object> = [
		{
			name: 'Round Peg ',
			content: 'description 1',
      type: TypeCheckEnum.Round
		},
		{
			name: 'Square Peg',
			content: 'description 2',
      type: TypeCheckEnum.Square
		},
	]
  constructor() { }


  private releaseDrop(event){
  	let index = this.itemsToDrop.indexOf(event);
  	if (index >= 0){
  		setTimeout(() => {(this.checkType(event,index),100)});
  	}
  }
  private checkType(event,index){
    if (event.type===this.dropItemType){
      this.itemsToDrop.splice(index,1);
    }
  }
  private startDrag(item){
    console.log('Begining to drag item: ' + item);
  }

}
.dragItem{
  border:1px solid #aaa;
  padding:2px 4px;
  margin:5px 0;
  width:90px;
  height:90px;
}
.dragItem-round{
  border-radius:45px;
}
.highlight{
	border:solid 1px #0d0;
}