Giter Site home page Giter Site logo

obaidurrehman / ng-drag-drop Goto Github PK

View Code? Open in Web Editor NEW
240.0 18.0 122.0 1.64 MB

Drag & Drop for Angular - based on HTML5 with no external dependencies. :tada:

License: MIT License

TypeScript 97.25% CSS 2.75%
draggable droppable drag-drop angular angular2 angular4 angular5 angular-components

ng-drag-drop's Introduction

Angular Drag & Drop

โš ๏ธ Discontinuation Notice

Almost 2 years ago I created this component to support HTML native drag drop in Angular. At that time there were a handful of libraries & they did not had the features I wanted. Today, with the release of Angular 7 & the CDK's drag drop component we finally have a much better alternative for this component. Please use Angular CDK's drag drop.

Join the chat at https://join.slack.com/t/ng-drag-drop/shared_invite/MjM5ODY5MDUyODY1LTE1MDUyOTk0OTMtNjFhZmJiOTE2Zg npm version npm downloads Build Status Codacy Badge

Drag & Drop for Angular, based on HTML5 with no external dependencies. Provides draggable & droppable directives. Features:

  • Transfer data from draggable to droppable.
  • Restrict drop based on drag-drop scopes.
  • Restrict drag to happen from either drag handles or the entire element.
  • Add custom drag Helper Image
  • Ability to add custom visual cue styles.

Demo

Content

  1. Demo
  2. Installation
  3. Usage
  4. Limitations
  5. Development
  6. API Doc
  7. Tips and Tricks

Demo

Check out the Plunker demo.

The demo folder of the repository contains the same demo as Plunkr that uses SystemJS. To run that demo do an npm install in that folder followed by npm start to serve the demo app.

Installation

npm install ng-drag-drop --save

Usage

Import default styles

Import style.css into your index.html. It has a set of default styles that will be applied upon drag operations. This is totally optional and you can modify the styles as per your need. See the Adding visual cues Section.

<link rel="stylesheet" href="node_modules/ng-drag-drop/style.css">

Update SystemJS config

If you use SystemJS as your module loader then you will need to update the config to load the ng-drag-drop module.

System.config({
    map: {
        'ng-drag-drop': 'node_modules/ng-drag-drop'
    },
    packages: {
        'ng-drag-drop':  { main: 'index.js',  defaultExtension: 'js' },
    }
});

Import NgDragDropModule

You need to import the NgDragDropModule in the module of your app where you want to use it.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { DemoComponent } from "./components/demo-component";
import { NgDragDropModule } from 'ng-drag-drop';


@NgModule({
  imports: [
      BrowserModule, 
      NgDragDropModule.forRoot()
  ],
  declarations: [DemoComponent],
  bootstrap: [DemoComponent]
})
export class AppModule {}

Use the draggable & droppable directives

Place the draggable directive on an element that you want to be draggable. The following example makes the List item draggable:

<ul>
  <li draggable>Coffee</li>
  <li draggable>Tea</li>
  <li draggable>Milk</li>
</ul>               

Similarly use the droppable directive on an element where you want to drop draggable:

<div droppable>
  <p>Drop items here</p>
</div>               

Restrict Drop based on Scopes

You can use the dragScope & dropScope property on draggable and droppable respectively to restrict user from dropping a draggable element into a droppable. The Scope properties can be string, an Array of string (to indicate multiple scope) or a function. The scopes must match in both to indicate compatible drag-drop zones.

In the following example, only the draggable with the drink dropScope can be dropped on the first droppable and both drink and meal can be dropped in the second one.

<ul>
  <li draggable [dragScope]="'drink'">Coffee</li>
  <li draggable [dragScope]="'drink'">Tea</li>
  <li draggable [dragScope]="'meal'">Biryani</li>
  <li draggable [dragScope]="'meal'">Kebab</li>
  ...
</ul>               
<div droppable [dropScope]="'drink'" [dragOverClass]="'drag-target-border'">
  <p>Only Drinks can be dropped in the above container</p>
</div>               

<div droppable [dropScope]="['drink', 'meal']" [dragOverClass]="'drag-target-border'">
  <p>Both Meal and Drinks can be dropped in the above container</p>
</div>               

Drop Scope as Functions

The DropScope of the droppable can be a function whose return value will determine if drop is allowed. This can be useful to implement complex logic that is otherwise not possible with string or array of string.

<div droppable [dropScope]="dropAllowed" [dragOverClass]="'drag-target-border'">
  <p>Only those items are droppable for which the `isDropAllowed()` function returns true</p>
</div>

Here is how the function is defined in the component:

export class MyComponent {
  val = 500;
  isDropAllowed = (dragData: any) => {
    return dragData > this.val;
  }
}

Notice how the function is defined as an Arrow Function. You need to do this so the lexical scope of this is preserved. You also get the dragData in the parameter so you can compare it with whatever you want.

If DropScope is a function, it can also return an Observable, which needs to later resolve to true or false. This can help in cases when you need to check asynchronously (eg: via http) whether the drop is allowed.

export class MyComponent {
  val = 500;
  isDropAllowed = (dragData: any) => {
    // Resolves to true or false after 1 second
    return Observable.of(dragData > this.val).delay(1000);
  }
}

Transfer Data via Drag Drop

You can transfer data from the draggable to the droppable via the dragData property on the draggable directive. The data will be received in the (onDrop) event of the droppable:

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

@Component({
    selector: 'app',
    template: `
<h3>Transfer Data via Drag Drop</h3>
<div class="row">
    <div class="col-sm-3">
        <ul class="list-group">
            <li draggable *ngFor="let item of items" [dragData]="item" class="list-group-item">{{item.name}}</li>
        </ul>
    </div>
    
    <div class="col-sm-3">
    <div class="panel panel-default" droppable (onDrop)="onItemDrop($event)">
        <div class="panel-heading">Drop Items here</div>
            <div class="panel-body">
                <li *ngFor="let item of droppedItems" class="list-group-item">{{item.name}}</li>
            </div>
        </div>
    </div>
</div>
`
})
export class AppComponent {
    items = [
            {name: "Apple", type: "fruit"},
            {name: "Carrot", type: "vegetable"},
            {name: "Orange", type: "fruit"}];
            
    onItemDrop(e: any) {
        // Get the dropped data here
        this.droppedItems.push(e.dragData);
    }
    constructor() { }
}             

Drag Handle

Drag Handle can be defined for a draggable item which will restrict drag of the element unless the item is dragged from the specified element. The handle should be a valid selector string. Example:

<li draggable [dragHandle]="'.drag-handle'">
   Not Draggable by list item but by the handle only.    
   <div class="pull-right"><i class="drag-handle fa fa-bars fa-lg" aria-hidden="true"></i></div> 
</li>               

Drag Helper Image

By default when an element is dragged, a translucent image is generated from the drag target. This image is generated automatically and varies with browser. A custom image can be used if desired. Pass the url of the image to [dragImage] on the draggable directive.

<li draggable [dragImage] = "'../../images/drag-helper.png'" >
   Not Draggable by list item but by the handle only.    
   <div class="pull-right"><i class="drag-handle fa fa-bars fa-lg" aria-hidden="true"></i></div> 
</li>               

Compatibility: This only works on Chrome & Firefox. Not supported on Edge.

Adding visual cues

Demo

Both the draggable & droppable directives take a bunch of inputs that let you apply class on various events. You can find the list below. Another thing you can do is clone the style.css that comes with this package and customize it as per your requirement.

Draggable Directive

  1. dragHandleClass
  2. dragClass
  3. dragTransitClass

Droppable Directive

  1. dragOverClass
  2. dragHintClass

Here is how a custom class is applied to a draggable element:

<div draggable [dragHandleClass]="'my-draggable'">
  <p>Drop items here</p>
</div>               

Limitations

This library uses Native Html5 drag & drop API to accomplish what it does. Because of this, certain aspects are not customizable and some UI behaviour is browser specific.

So if you were to see the demo under Edge or Chrome/Firefox you'll see that these browsers show a different behaviour when an Item is being dragged. Simlarly Edge does not let you set a custom dragImage while others do. Another major issues is that we can't control the opacity of the ghost element of item being dragged.

To overcome these issues we'll need to implement our own drag drop functionality instead of relying on the Native Html API which at this point in time, is beyond the scope of this component. Libraries like Dragula, JQuery Draggable, Interact.js to name a few, can provide you with alternatives.

Touch Support

HTML5 Drag drop is not touch supported but you can use the DragDropTouch Polyfill.

Development

To start the dev flow on your system, follow these steps:

  1. npm install on the root of this repo.
  2. npm install in the demo folder. This is where the demo app resides. Sort of a test & play yard for ng-drag-drop package.
  3. Next you need to sym-link your package with the demo folder so your changes to the package are reflected in the demo app. Please remember the demo and the package are seperate apps & the demo app does not get published to npm. To link run npm link on the root of the repo followed by npm link ng-drag-drop in demo folder. You can read more about npm link here.
  4. Finally run npm run dev at the root. This will open up the demo app in browser.
  5. Now you can make changes to the actual component or the demo app and debug. Please note that changing the code of demo app will autoreload the browser but you'll need to manually refresh the page if you change the component code.

Note: The steps are a bit involved at this time and will be simplified to an npm script in later releases.

API Doc

Draggable directive

Attributes

Name Type Default Value Description
dragData any null The data that will be avaliable to the droppable directive on its onDrop() event.
dragScope `string Array` 'default'
dragClass (previously dragOverClass) string 'drag-border' CSS class applied on the draggable that is applied when the item is being dragged.
dragTransitClass string 'drag-transit' CSS class applied on the drag helper translucent element clone.
dragHandleClass string 'drag-handle' The CSS class applied to a draggable element. If a dragHandle is defined then its applied to that handle element only. By default it is used to change the mouse over pointer.
draghandle string null The selector that defines the drag Handle. If defined drag will only be allowed if dragged from the selector element.
dragImage string null The url to image that will be used as custom drag image when the draggable is being dragged.
dragEnabled boolean true Defines if drag is enabled. true by default.

Events

Name Parameters Description
onDragStart e: DOM event Event fired when Drag is started
onDrag e: DOM event Event fired while the element is being dragged
onDragEnd e: DOM event Event fired when dragged ends

For more information on Drag DOM Events: Drag Event

Droppable directive

Attributes

Name Type Default Value Description
dropScope `string Array` 'default'
dragOverClass string 'drag-over-border' CSS class applied on the droppable element when the item is being dragged over valid drop target.
dragHintClass string 'drag-hint-border' CSS class applied on this droppable when a compatible draggable item is being dragged. This can be used to visually show allowed drop zones.
dropEnabled boolean true Defines if drop is enabled. true by default.

Events

Name Parameters Description
onDragEnter e: DOM event Event fired when Drag dragged element enters a valid drop target.
onDragOver e: DOM event Event fired when an element is being dragged over a valid drop target.
onDragLeave e: DOM event Event fired when a dragged element leaves a valid drop target.
onDrop e: DropEvent Event fired when an element is dropped on a valid drop target.

Tips And Tricks

Change cursor to "move" or "copy" when Ctrl-key is pressed/released

In Chrome and Edge (Windows 10 - not tested in other browser/OS), when you drag an element, the cursor changes to "move" whether or not you press the Ctrl-key.

Fortunately, it's easy to change this behavior.

On the draggable element, you bind to the events "onDragStart", "onDragOver", "onDragLeave", and manipulate the cursor in the bound method of the component.

So, in the template :

  <div class="some-class" draggable 
    (onDragStart)="onItemDragStart($event)" (onDragOver)="onItemDragOver($event)" (onDragLeave)="onItemDragLeave($event)">
    <!-- some content here -->
  </div>

And in the *.ts file :

    onItemDragStart(event) {
      event.dataTransfer.dropEffect = event.ctrlKey ? 'copy' : 'move';
    }

    onItemDragOver(event) {
      event.dataTransfer.dropEffect = event.ctrlKey ? 'copy' : 'move';
    }

    onItemDragLeave(event) {
      event.dataTransfer.dropEffect = event.ctrlKey ? 'copy' : 'move';
    }

In the droppable element, here's how you find if the Ctrl-key is pressed or not :

In the template :

  <div class="some-other-class" droppable (onDrop)="onItemDrop($event)">
    <!-- some content here -->
  </div>

In the component's *.ts file :

    onItemDrop(event) {
      const isCopy = event.nativeEvent.ctrlKey;
      // do something with the dropped item
    }

License

MIT

ng-drag-drop's People

Contributors

akagr avatar aleclerctekaris avatar andreialecu avatar dingweizhe avatar gitter-badger avatar greenkeeper[bot] avatar jaromirdeak avatar mselerin avatar nipuna-g avatar obaidurrehman avatar progdom avatar rgant avatar sickewesterdijk avatar sypher1987 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ng-drag-drop's Issues

Different CSS to the draggable element while in transit

[x] feature request

On some apps we use dragging to transform an element into another. dragClass apply CSS to the element that is being dragglabe and the element in transit. It would be great if whe could apply CSS to both separately. On this way, the css in the element dragabled is different from the element in transit.

drag and drop in multiple component

I have two component for example
one.ts
tasks[]
tasks ={"A","B"}
two.ts
tasks[]
when I drop one element i.e A from one.ts to two.ts it should remove from one.ts and vice versa.

dragImage - what if I have a spritesheet?

In my case, I use a big spritesheet of images for my drag and drop items. You can move them from one grid to another. If I drag/drop them, the resulting placeholder image is the WHOLE spritesheet - is it possible to make it just the current image (or maybe copy the div that it's in and use that to drag)?

Items are not visible properly while dragging in certain resolutions

Items which I'm dragging are not visible properly in big screens. Even I noticed the same problem in your plunker example.

In your plunker I did below steps

Step 1: Click launch the preview in a separate window
--> full screen window will open

Step2: Now drag an item from the list and notice dragged item is not visible properly.

Even I'm facing the same issue in my current project also where I implemented ng2-drag-drop.

Thanks
Pratap A.K

CSS is not working in large display screen

Hi Obaid,

I found the when we are trying to drag the element then the dashed box will be visible around the dragged element also we can see the element shadow which is dragged.

But, i large display its not working only the box is visible artificially. I don't know whether this is a bug or not but i found it is happening in the plunker example also.

DragImage to be string/label ?

Hi, is there any way where I can customize the dragImage to show a custom string? For example if I drag "item A", i want to show "Dragging item A" and if I drag "item B", i want to show "Dragging item B"?
Other than custom string, can i customize how the dragImage looks like using html controls like div, label, etc?

Touch enabled

It would be great to have this library touch screen enabled (use swipes for drag and drop). Any plan for this?

Issue when item is draggable and droppable

Is this feature not supported right now?

Because I marked a div as both draggable and droppable then I get the error below:

SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse ()
at Droppable.drop (droppable.js:51)
at Wrapper_Droppable.handleEvent (/Ng2DragDropModule/Droppable/wrapper.ngfactory.js:74)
at View_NavverItemComponent3.handleEvent_0 (/DashboardModule/NavverItemComponent/component.ngfactory.js:708)

Thank you!

Feature request: dropScope function

It would be great if we could attach a function to dropScope or equivalent, which would get to examine the dragData and determine dynamically if a drop should be allowed.

Error: Uncaught (in promise): Error: No provider for Ng2DragDropService!

I am using ng2-drag-drop package in my angular 4 app, i have deployed to staging, the package works fine, but yesterday i deployed it live and started getting the error:
Error: Uncaught (in promise): Error: No provider for Ng2DragDropService!

can you please help me to get out of this ASAP
Thanks,
Looking Forward

Can we disable any droppable container

Hello All,

Can we have an option to disable to non-selected droppable container. Let's say we have two droppable container and i want to allow drop only on the selected container. The other container which is not selected i want to disable the drop functionality.

Error: Unexpected value 'Ng2DragDropModule' imported by the module

Trying to use it angular2 app generated by angular cli. Default setup (with webpack).
Installed module via npm and trying to import to my app module:
imports: [Ng2DragDropModule]

Everything compiles fine but in browser I got:
Error: Unexpected value 'Ng2DragDropModule' imported by the module 'AppModule'

Importing module like so:
import { Ng2DragDropModule } from 'ng2-drag-drop'

Do you know what it can be?

Thanks for the module btw =)

How to disable drag (draggable = false or true)

Hello,

I want to set draggable to false or true based on some condition can i be done?

<li draggable *ngFor="let device of lmsDeviceList"
               [dragOverClass]="'drag-over-border-device'"
               [dragData]="device"
               [dragScope]="'zone' "                              
               > 

'draggable' doesn't disable

I have a draggable div (that is actually images)

 <div draggable *ngFor="let card of player.cardHand" [dragData]="card" class="drag-div">
   <img src="{{cardBluePath + card.fileName}}" class="dragged">
 </div>

They can be dropped on to any of 9 available div's (slots), which populates the droppedItems list (and uses a pipe to filter the object based on the slot

        <div class="slot2" id="slot2" droppable (onDrop)="onItemDrop($event, '2')">
          <div class="panel-body">
            <div *ngFor="let card of droppedItems | slotFilter:{slot:'2'}" class="list-group-item">
              <img src="{{cardBluePath + card.fileName}}"><br>
            </div>
          </div>
        </div>

Once an item is dropped onto a slot, I don't want it to be draggable again. Once it's there, it needs to stay there. Reading the documentation, I thought I needed to set the [draggable] to false, so I did this:

        <div class="slot1" id="slot1" droppable (onDrop)="onItemDrop($event, '1')" [draggable]="false">
          <div class="panel-body" [draggable]="false">
            <div [draggable]="false" *ngFor="let card of droppedItems | slotFilter:{slot:'1'}" class="slot">
              <img src="{{cardBluePath + card.fileName}}" class="dropped" [draggable]="false"><br>
            </div>
          </div>
        </div>

However, the image is still being allowed to be dragged and inspecting the elements, the draggable tag is still = true, even though I am explicitly setting it to false on every element in the block.

Is this an issue, or am I doing something wrong?

Angular 1.x

Hi, awesome directives! Any chances this is available to Angular 1.x versions too?

I'm a total noob in Angular 2, don't even know if there is something that restricts that, or if its easy like rendering typescript to javascript, then making some basic changes.

Thanks

Sortable: Restrict multi list re-order by default

The sortable directive must be single list sortable by default unless configured i.e. Items should be re-orderable with the list only. Right now this is not the default behavior.

Kinda like scopes. Not sure how we should approach this. I am open to ideas.

Error in ngOnDestroy() method of Droppable directive while doing unit test

Hello,

I'm using your excellent ng2-drag-drop module in an application.
Today I started to create some tests in my Angular 2 app.

I have a panel which is draggable from a left sidebar to the main panel is the center.

But, when it comes to test my component containing droppable div, the command "ng test" try to run the default test "should create" of my component and it stopped with the following errors :

Chrome 59.0.3071 (Windows 10 0.0.0) ChartPanelToolbarComponent should create FAILED
        TypeError: Cannot read property 'unsubscribe' of undefined
            at Droppable.ngOnDestroy (webpack:///~/ng2-drag-drop/src/directives/droppable.directive.js:57:0 <- src/test.ts:110419:35)
            at Wrapper_Droppable.ngOnDestroy (/Ng2DragDropModule/Droppable/wrapper.ngfactory.js:17:16)
            at CompiledTemplate.proxyViewClass.View_GridPanelComponent0.destroyInternal (/GridPanelModule/GridPanelComponent/component.ngfactory.js:185:23)
            at CompiledTemplate.proxyViewClass.AppView.destroy (webpack:///~/@angular/core/src/linker/view.js:203:0 <- src/test.ts:93603:14)
            at CompiledTemplate.proxyViewClass.DebugAppView.destroy (webpack:///~/@angular/core/src/linker/view.js:606:0 <- src/test.ts:94006:38)
            at CompiledTemplate.proxyViewClass.View_AppComponent0.destroyInternal (/DynamicTestModule/AppComponent/component.ngfactory.js:302:20)
            at CompiledTemplate.proxyViewClass.AppView.destroy (webpack:///~/@angular/core/src/linker/view.js:203:0 <- src/test.ts:93603:14)
            at CompiledTemplate.proxyViewClass.DebugAppView.destroy (webpack:///~/@angular/core/src/linker/view.js:606:0 <- src/test.ts:94006:38)
            at CompiledTemplate.proxyViewClass.View_AppComponent_Host0.destroyInternal (/DynamicTestModule/AppComponent/host.ngfactory.js:33:19)
            at CompiledTemplate.proxyViewClass.AppView.destroy (webpack:///~/@angular/core/src/linker/view.js:203:0 <- src/test.ts:93603:14)
            at CompiledTemplate.proxyViewClass.DebugAppView.destroy (webpack:///~/@angular/core/src/linker/view.js:606:0 <- src/test.ts:94006:38)
            at CompiledTemplate.proxyViewClass.AppView.detachAndDestroy (webpack:///~/@angular/core/src/linker/view.js:187:0 <- src/test.ts:93587:14)
            at ComponentRef_.destroy (webpack:///~/@angular/core/src/linker/component_factory.js:147:51 <- src/test.ts:42620:70)
            at ComponentFixture.destroy (webpack:///~/@angular/core/bundles/core-testing.umd.js:263:0 <- src/test.ts:12171:35)
            at webpack:///~/@angular/core/bundles/core-testing.umd.js:728:61 <- src/test.ts:12636:78

When I remove the "droppable" attribute in my div, the test pass.

I'm using Angular CLI 1.0.0-beta.28.3 and ng2-drag-drop 2.0.1

You can reproduce it with the following steps :

npm install -g [email protected]
ng new ng2-drag-drop-test-app
cd ng2-drag-drop-test-app
npm install ng2-drag-drop --save
ng generate module subcomponent
ng generate component subcomponent
ng generate module sidebar
ng generate component sidebar

Then edit some files :

src/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { SubcomponentModule } from './subcomponent/subcomponent.module';
import { SidebarModule } from './sidebar/sidebar.module';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    SubcomponentModule,
    SidebarModule
  ],
  providers: [],
  bootstrap: [AppComponent],
  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class AppModule { }

src/app/app.component.html

<app-sidebar></app-sidebar>
<app-subcomponent></app-subcomponent>

src/app/app.component.spec.ts

/* tslint:disable:no-unused-variable */
import { DebugElement, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { SubcomponentModule } from './subcomponent/subcomponent.module';
import { SidebarModule } from './sidebar/sidebar.module';

describe('AppComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
      imports: [
        SubcomponentModule,
        SidebarModule
      ],
      schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
    });
    TestBed.compileComponents();
  });

  it('should create the app', async(() => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  }));
});

src/app/sidebar/sidebar.module.ts

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Ng2DragDropModule } from 'ng2-drag-drop';

import { SidebarComponent } from './sidebar.component';

@NgModule({
  imports: [
    CommonModule,
    Ng2DragDropModule
  ],
  exports: [
    SidebarComponent
  ],
  declarations: [SidebarComponent],
  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class SidebarModule { }

src/app/sidebar/sidebar.component.ts

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

@Component({
  selector: 'app-sidebar',
  templateUrl: './sidebar.component.html',
  styleUrls: ['./sidebar.component.css']
})
export class SidebarComponent implements OnInit {
  items = [{name: 'Apple', type: 'fruit'},
          {name: 'Carrot', type: 'vegetable'},
          {name: 'Orange', type: 'fruit'}];

  constructor() { }

  ngOnInit() {
  }

}

src/app/sidebar/sidebar.component.html

<div class="col-sm-3">
    <ul class="list-group">
        <li draggable *ngFor="let item of items" [dragData]="item" class="list-group-item">{{item.name}}</li>
    </ul>
</div>

src/app/sidebar/sidebar.component.spec.ts

/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';

import { SidebarComponent } from './sidebar.component';
import { Ng2DragDropModule } from 'ng2-drag-drop';

describe('SidebarComponent', () => {
  let component: SidebarComponent;
  let fixture: ComponentFixture<SidebarComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ SidebarComponent ],
      imports: [
        Ng2DragDropModule
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(SidebarComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

src/app/subcomponent/subcomponent.module.ts

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Ng2DragDropModule } from 'ng2-drag-drop';

import { SubcomponentComponent } from './subcomponent.component';

@NgModule({
  imports: [
    CommonModule,
    Ng2DragDropModule
  ],
  exports: [
    SubcomponentComponent
  ],
  declarations: [SubcomponentComponent],
  schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class SubcomponentModule { }

src/app/subcomponent/subcomponent.component.ts

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

@Component({
  selector: 'app-subcomponent',
  templateUrl: './subcomponent.component.html',
  styleUrls: ['./subcomponent.component.css']
})
export class SubcomponentComponent implements OnInit {
  droppedItems = [];

  constructor() { }

  ngOnInit() {
  }

  onItemDrop(e: any) {
      // Get the dropped data here
      this.droppedItems.push(e.dragData);
  }
}

src/app/subcomponent/subcomponent.component.spec.ts

/* tslint:disable:no-unused-variable */
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';

import { SubcomponentComponent } from './subcomponent.component';
import { Ng2DragDropModule } from 'ng2-drag-drop';

describe('SubcomponentComponent', () => {
  let component: SubcomponentComponent;
  let fixture: ComponentFixture<SubcomponentComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ SubcomponentComponent ],
      imports: [
        Ng2DragDropModule
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(SubcomponentComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

src/app/subcomponent/subcomponent.html.ts

<div class="panel panel-default" droppable (onDrop)="onItemDrop($event)">
  <div class="panel-heading">Drop Items here</div>
  <div class="panel-body">
      <li *ngFor="let item of droppedItems" class="list-group-item">{{item.name}}</li>
  </div>
</div>

Then run ng test and see the errors :)
I have a different error with this test I've created for this posts, but it's still the same about the droppable div.
If i remove "droppable" attribute from the div inside the subcomponent component, then the test passes.

Sorry for the long post, i didn't find the way to do these tests on plunker

Droppable unsubscribed and fails on subsequent calls to page

When I leave and enter a page multiple times, I am getting an object unsubscribed error from the droppable directive. The usage looks like:

`<div class="empty-document-view-item"
droppable
(onDrop)="onItemDrop($event)">
Drag and drop documents here to create summary.

`

The error I am seeing is:

`ERROR Error: Uncaught (in promise): ObjectUnsubscribedError: object unsubscribed
Error: object unsubscribed
at ObjectUnsubscribedError.ZoneAwareError (zone.js:917)
at new ObjectUnsubscribedError (:11000/lib/rxjs/util/ObjectUnsubscribedError.js:19)
at Subject._trySubscribe (:11000/lib/rxjs/Subject.js:94)
at Subject.Observable.subscribe (:11000/lib/rxjs/Observable.js:45)
at Droppable.ngOnInit (:11000/lib/ng2-drag-drop/src/directives/droppable.js:38)
at checkAndUpdateDirectiveInline (:11000/lib/@angular/core/bundles/core.umd.js:10718)
at checkAndUpdateNodeInline (:11000/lib/@angular/core/bundles/core.umd.js:12097)
at checkAndUpdateNode (:11000/lib/@angular/core/bundles/core.umd.js:12065)
at debugCheckAndUpdateNode (:11000/lib/@angular/core/bundles/core.umd.js:12694)
at debugCheckDirectivesFn (:11000/lib/@angular/core/bundles/core.umd.js:12635)
at Object.eval [as updateDirectives] (ng:///HomeComponentModule/DocumentViewerComponent.ngfactory.js:151)
at Object.debugUpdateDirectives [as updateDirectives] (:11000/lib/@angular/core/bundles/core.umd.js:12620)
at checkAndUpdateView (:11000/lib/@angular/core/bundles/core.umd.js:12032)
at callViewAction (:11000/lib/@angular/core/bundles/core.umd.js:12347)
at execComponentViewsAction (:11000/lib/@angular/core/bundles/core.umd.js:12293)
at ObjectUnsubscribedError.ZoneAwareError (zone.js:917)
at new ObjectUnsubscribedError (:11000/lib/rxjs/util/ObjectUnsubscribedError.js:19)
at Subject._trySubscribe (:11000/lib/rxjs/Subject.js:94)
at Subject.Observable.subscribe (:11000/lib/rxjs/Observable.js:45)
at Droppable.ngOnInit (:11000/lib/ng2-drag-drop/src/directives/droppable.js:38)
at checkAndUpdateDirectiveInline (:11000/lib/@angular/core/bundles/core.umd.js:10718)
at checkAndUpdateNodeInline (:11000/lib/@angular/core/bundles/core.umd.js:12097)
at checkAndUpdateNode (:11000/lib/@angular/core/bundles/core.umd.js:12065)
at debugCheckAndUpdateNode (:11000/lib/@angular/core/bundles/core.umd.js:12694)
at debugCheckDirectivesFn (:11000/lib/@angular/core/bundles/core.umd.js:12635)
at Object.eval [as updateDirectives] (ng:///HomeComponentModule/DocumentViewerComponent.ngfactory.js:151)
at Object.debugUpdateDirectives [as updateDirectives] (:11000/lib/@angular/core/bundles/core.umd.js:12620)
at checkAndUpdateView (:11000/lib/@angular/core/bundles/core.umd.js:12032)
at callViewAction (:11000/lib/@angular/core/bundles/core.umd.js:12347)
at execComponentViewsAction (:11000/lib/@angular/core/bundles/core.umd.js:12293)
at resolvePromise (zone.js:712) [angular]
at resolvePromise (zone.js:683) [angular]
at :11000/lib/zone.js/dist/zone.js:760:17 [angular]
at Object.onInvokeTask (:11000/lib/@angular/core/bundles/core.umd.js:4123) [angular]
at ZoneDelegate.invokeTask (zone.js:397) [angular]
at Zone.runTask (zone.js:165) [ => angular]
at drainMicroTaskQueue (zone.js:593) []
at ZoneTask.invoke (zone.js:464) []
at timer (zone.js:1540) []
defaultErrorLogger @ :11000/lib/@angular/core/bundles/core.umd.js:1091
ErrorHandler.handleError @ :11000/lib/@angular/core/bundles/core.umd.js:1151
next @ :11000/lib/@angular/core/bundles/core.umd.js:4761
schedulerFn @ :11000/lib/@angular/core/bundles/core.umd.js:3835
SafeSubscriber.__tryOrUnsub @ :11000/lib/rxjs/Subscriber.js:236
SafeSubscriber.next @ :11000/lib/rxjs/Subscriber.js:185
Subscriber._next @ :11000/lib/rxjs/Subscriber.js:125
Subscriber.next @ :11000/lib/rxjs/Subscriber.js:89
Subject.next @ :11000/lib/rxjs/Subject.js:55
EventEmitter.emit @ :11000/lib/@angular/core/bundles/core.umd.js:3821
NgZone.triggerError @ :11000/lib/@angular/core/bundles/core.umd.js:4192
onHandleError @ :11000/lib/@angular/core/bundles/core.umd.js:4153
ZoneDelegate.handleError @ zone.js:369
Zone.runGuarded @ zone.js:141
_loop_1 @ zone.js:604
drainMicroTaskQueue @ zone.js:613
ZoneTask.invoke @ zone.js:464
timer @ zone.js:1540'

Notice the error Droppable.ngOnInit (:11000/lib/ng2-drag-drop/src/directives/droppable.js:38).

The line is

this.ng2DragDropService.onDragStart.subscribe(function () {

which is unsubscribed when I leave the page the first time. I wasn't sure if I was missing something or not.

Thanks.

dragOverClass assigned to non valid drop targets

If I assign the dragOverClass to a draggable (and droppable) element it gets the class assigned at drag start and short after again removed. The draggable helper has now the dragOverClass style.

Drag and Drop Taking More time for large set of data

Hello Obaid,

I am using this library from past 6 month and till now it's very good. But, as my application is growing with huge data sets then drag and drop is taking too much time. Lets say i have 2000 item in a list to drag any item from list and drop it to some area its taking 20-30 seconds, can you suggest what to do in this case?

Feature: Add custom dragHelper functionality

The draggable directive should take a dragHelper input that should be a TemplateRef. One should be able to define this in the markup:

<div #myHelper>I am a custom DragHelper</div>

and be able to use it as custom dragHelper. We should also add a default dragHandler that should be a clone of the element since the current one sometimes becomes too transparent to provide a good visual feedback.

Plunker has no items

I'm trying to use your Plunker demo and there are no items populated to drag or drop. I've tried this on multiple browsers (Chrome, Safari) and it doesn't seem that it works on any of them. The code seems to indicate that, for example, the vegetable array exists and is trying to populate into the first draggable field. However, even when I put extra dummy text into the li element, no elements display, seeming to indicate that there is nothing in vegetables.
The display looks like this:
screen shot 2017-07-31 at 10 41 57 am

Add Universal support

Version: 2.6.0
Angular 4.3.5
AngularCli: 1.4.0-rc.1

When running on universal I get the following error

ERROR TypeError: this.el.nativeElement.querySelector is not a function
    at Draggable.getDragHandleElement (C:\dev\git_clones\app\node_modules\ng2-drag-drop\src\directives\draggable.directive.js:136:49)
    at Draggable.applyDragHandleClass (C:\dev\git_clones\app\node_modules\ng2-drag-drop\src\directives\draggable.directive.js:125:32)
    at Draggable.set [as dragEnabled] (C:\dev\git_clones\app\node_modules\ng2-drag-drop\src\directives\draggable.directive.js:72:18)

It does not work with SVG

The drag and drop doesn't work properly if you drop in a svg. Sometimes you can drop, but mostly not.

Sortable: Items duplicate when being reordered

This is a bit tricky to reproduce.

The sortable directive duplicates item in the list when being re-ordered. It's a bit tricky to reproduce but if items are repeatedly re-ordered in succession it will end with duplicate items in the list.

Some thing like this:

duplicate

I can't seem to figure out the root cause of this.

Droppable not working between different components.

Is it possible to drag and drop items from different components? I'am able to fire off an OnDragStart event. But when I drop the item into the droppable area it doesn't fire off the onDrop event.

Example: I'm trying this in the ng2-Admin project where my items that are draggable are in the blue dashboard area and my droppable area is the black sidebar to the left. If I take an item from the dashboard I get the onDragStart event, but when I drop it onto the left sidebar, the onDrop event doesn't fire.

Drag handle intermittently not working

I have come across an issue with the drag handles, because the current target that is used for the drag handles is updated on mouseover and the drag start requires movement of the mouse to initiate sometimes it does not work. The tracked current target can get updated when the mouse moves off the drag handle before the drag star event fires. This can be seen on the plunkr demo if you click and drag quickly using the drag handle.

I have made a fix in my fork of the project and issued a pull request (#88).

Drag drop not supported in all browsers

Currently I have implemented DnD by importing 'Ng2DragDropModule', its working fine in chrome and mozilla.
But not supported in safari and ms edge browser.
Please guide where we have to change to support all browsers.

Demo is using angular2.4.0, not angular4.0.0

I am new to Angular, the ng2-drag-drop is using angular 4.0.0, but the demo is using angular 2.4.0, would you please upgrade the demo to angular 4.0.0?

Also another newbie question, after I build the ng2-drag-drop, how do I use it in a separate angular project? like in java, I can build something into a jar file, then I can drop the jar file to a separate project and import it there, how does it work for ng2-drag-drop? what file is generated for me to import from a separate project?

Thanks

Error compiling with angular version 4

I'm getting this error after importing the module:

ERROR in Error encountered resolving symbol values statically. Calling function 'makeDecorator', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol NgModule

Using angular4.0.0 with angular cli 1.0.0

Highlight valid drop targets

It would be nice if we can assign a class to all valid drop targets if drag is started. It brings more usability to the user.

Error: Template parse errors: 'drag-helper' is not a known element:

Hi all,
I am trying to use ng2-drag-drop in my angular 4 project, I copied the whole folder of drag-help of the demo project to my project and added to my app.component.html, drag-helper.component.ts has selector: 'drag-helper', but after I build and start ng server, in my browser, I got this error:

Error: Template parse errors:
'drag-helper' is not a known element:

  1. If 'drag-helper' is an Angular component, then verify that it is part of this module.
  2. If 'drag-helper' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@NgModule.schemas' of this component to suppress this message.

Any clue?
Thanks

Compilation Error in AOT build.

Drag and Drop run and work correctly with JIT compilation But Its through following error in AOT compilation.

Error: Error encountered resolving symbol values statically. Reference to a local (non-exported) symbol 'Ng2DragDropModule'. Consider exporting the symbol (position 21:14 in the original .ts file), resolving symbol Ng2DragDropModule in /home/shamim/Boi2/boibazar/node_modules/ng2-drag-drop/src/ng2-drag-drop.module.d.ts, resolving symbol Ng2DragDropModule in /home/shamim/Boi2/boibazar/node_modules/ng2-drag-drop/index.d.ts, resolving symbol PublicPageModule in /home/shamim/Boi2/boibazar/src/app/pages/public-page/public-page.module.ts, resolving symbol PublicPageModule in /home/shamim/Boi2/boibazar/src/app/pages/public-page/public-page.module.ts

OS: Ubuntu 16.04,
Node version : 6.9.5,
NPM: 3.10.10.
Angular version: 2.4.7

Uncaught ReferenceError: exports is not defined

I am using [email protected]
My index.js looks as follows:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ng2_drag_drop_module_1 = require("./src/ng2-drag-drop.module");
exports.Ng2DragDropModule = ng2_drag_drop_module_1.Ng2DragDropModule;
//# sourceMappingURL=index.js.map

The bold line causes the issue, from some initial research I suppose this is a typescript setting, I am not sure if I follow, if it helps here is the ts config:

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "baseUrl": "src",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2016",
      "dom"
    ],
    "plugins": [
      { "name": "tslint-language-service"}
    ]
  }
}```

Drag Multiple Item

Is there is anyway to drag multiple selected item from one list to another list

Replace instead of sorting

Dear ObaidUrRehman,

I have a requirement to replace the rows instead of sorting in an order. Am i doing a component which is for mapping while drag and drop it changes the order instead of replacing the index. Kindly help me it is possible to replace the item index instead of sorting.

How to know in which array dropped?

I'm writing a dorm mgmt website using ang2. It will show couple of rooms of a building on the right panel, and students on the left. When I drag a student over to one of the rooms, how can I know which room it's dropped.

This drag and drop api is awesome, but it seems to need to know the array name of the droppable. What if the droppable belongs to a parent array. How can I know which room dropped?

Thanks,
Kevin

Make scope an array of string

dropScope for droppable directive is a string.
can you make it an array for strings so that droppable directive can accept more than 1 type of items?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.