Convert Figma logo to code with AI

marceljuenemann logoangular-drag-and-drop-lists

Angular directives for sorting nested lists using the HTML5 Drag & Drop API

2,158
714
2,158
161

Top Related Projects

29,570

Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.

21,948

:ok_hand: Drag and drop so simple it hurts

Beautiful and accessible drag and drop for lists with React

A set of higher-order components to turn any list into an animated, accessible and touch-friendly sortable list✌️

Component infrastructure and Material Design components for Angular

Quick Overview

Angular-drag-and-drop-lists is a lightweight Angular module that enables drag and drop functionality for nested lists. It provides a simple and flexible way to implement sortable lists, kanban boards, and other drag-and-drop interfaces in Angular applications.

Pros

  • Easy to integrate with existing Angular projects
  • Supports nested lists and complex drag-and-drop scenarios
  • Lightweight with no external dependencies
  • Highly customizable with various configuration options

Cons

  • Limited to Angular applications (not usable with other frameworks)
  • May require additional styling for optimal visual appearance
  • Documentation could be more comprehensive
  • Not actively maintained (last update was in 2019)

Code Examples

  1. Basic list setup:
<ul dnd-list>
  <li *ngFor="let item of items" dnd-draggable [dragData]="item">
    {{item.name}}
  </li>
</ul>
  1. Handling drop events:
<ul dnd-list (dndDrop)="onDrop($event)">
  <!-- List items -->
</ul>
onDrop(event: DndDropEvent) {
  if (event.isExternal) {
    this.items.push(event.data);
  } else {
    moveItemInArray(this.items, event.index, event.currentIndex);
  }
}
  1. Customizing drag handle:
<li dnd-draggable [dragEnabled]="true">
  {{item.name}}
  <span dnd-handle class="handle">::</span>
</li>

Getting Started

  1. Install the package:

    npm install angular-drag-and-drop-lists
    
  2. Import the module in your app.module.ts:

    import { DndListModule } from 'angular-drag-and-drop-lists';
    
    @NgModule({
      imports: [
        // other imports
        DndListModule
      ],
    })
    export class AppModule { }
    
  3. Use the directives in your component template:

    <ul dnd-list>
      <li *ngFor="let item of items" dnd-draggable [dragData]="item">
        {{item.name}}
      </li>
    </ul>
    
  4. Handle events in your component:

    import { DndDropEvent } from 'angular-drag-and-drop-lists';
    
    export class MyComponent {
      items = [/* your list items */];
    
      onDrop(event: DndDropEvent) {
        // Handle the drop event
      }
    }
    

Competitor Comparisons

29,570

Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.

Pros of Sortable

  • Framework-agnostic, works with vanilla JavaScript and various frameworks
  • More extensive features, including multi-drag, swap, and animation options
  • Larger community and more frequent updates

Cons of Sortable

  • Steeper learning curve due to more complex API
  • Requires additional setup for Angular integration

Code Comparison

angular-drag-and-drop-lists:

<ul dnd-list="list">
    <li ng-repeat="item in list"
        dnd-draggable="item"
        dnd-moved="list.splice($index, 1)"
        dnd-effect-allowed="move">
        {{item.label}}
    </li>
</ul>

Sortable:

<ul id="items">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
</ul>

<script>
new Sortable(document.getElementById('items'), {
    animation: 150,
    ghostClass: 'blue-background-class'
});
</script>

The angular-drag-and-drop-lists example shows tighter Angular integration, while Sortable demonstrates its framework-agnostic nature. Sortable requires separate JavaScript initialization but offers more customization options.

21,948

:ok_hand: Drag and drop so simple it hurts

Pros of Dragula

  • Framework-agnostic, works with any JavaScript project
  • Lightweight and minimalistic, with a small footprint
  • Extensive customization options and API

Cons of Dragula

  • Requires more setup for Angular-specific features
  • Less integrated with Angular's change detection system
  • May need additional work for complex nested structures

Code Comparison

angular-drag-and-drop-lists:

<ul dnd-list="list">
  <li ng-repeat="item in list"
      dnd-draggable="item"
      dnd-moved="list.splice($index, 1)"
      dnd-effect-allowed="move">
    {{item.label}}
  </li>
</ul>

Dragula:

dragula([document.querySelector('#left'), document.querySelector('#right')])
  .on('drop', function (el) {
    el.className += ' ex-moved';
  });

The angular-drag-and-drop-lists example shows tight integration with Angular directives, while Dragula demonstrates a more JavaScript-centric approach that can be used with any framework or vanilla JS.

angular-drag-and-drop-lists is specifically designed for Angular applications, offering seamless integration with Angular's ecosystem. It provides directives that can be easily added to existing Angular templates.

Dragula, on the other hand, offers a more flexible solution that can be implemented in various environments. It requires manual DOM selection and event handling but provides greater control over the drag-and-drop behavior.

Beautiful and accessible drag and drop for lists with React

Pros of react-beautiful-dnd

  • Smooth, natural-feeling animations and transitions
  • Extensive accessibility features and keyboard support
  • Comprehensive documentation and examples

Cons of react-beautiful-dnd

  • Limited to vertical lists and horizontal lists (no grids)
  • Steeper learning curve due to more complex API
  • Larger bundle size compared to angular-drag-and-drop-lists

Code Comparison

react-beautiful-dnd:

<DragDropContext onDragEnd={this.onDragEnd}>
  <Droppable droppableId="list">
    {(provided) => (
      <div {...provided.droppableProps} ref={provided.innerRef}>
        {this.state.items.map((item, index) => (
          <Draggable key={item.id} draggableId={item.id} index={index}>
            {(provided) => (
              <div
                ref={provided.innerRef}
                {...provided.draggableProps}
                {...provided.dragHandleProps}
              >
                {item.content}
              </div>
            )}
          </Draggable>
        ))}
        {provided.placeholder}
      </div>
    )}
  </Droppable>
</DragDropContext>

angular-drag-and-drop-lists:

<ul dnd-list="list">
  <li ng-repeat="item in list"
      dnd-draggable="item"
      dnd-moved="list.splice($index, 1)"
      dnd-effect-allowed="move"
      dnd-selected="models.selected = item"
      ng-class="{'selected': models.selected === item}">
    {{item.label}}
  </li>
</ul>

The code comparison shows that react-beautiful-dnd requires more setup and nesting, while angular-drag-and-drop-lists has a simpler structure. However, react-beautiful-dnd offers more granular control over the drag and drop behavior.

A set of higher-order components to turn any list into an animated, accessible and touch-friendly sortable list✌️

Pros of react-sortable-hoc

  • Built specifically for React, offering seamless integration with React components
  • Supports both vertical and horizontal sorting out of the box
  • Provides a higher-order component (HOC) approach, allowing for more flexible and reusable code

Cons of react-sortable-hoc

  • Limited to sorting functionality, while angular-drag-and-drop-lists offers both dragging and dropping
  • May require additional setup for complex nested list structures
  • Less suitable for non-React projects or those with mixed framework environments

Code Comparison

react-sortable-hoc:

import { SortableContainer, SortableElement } from 'react-sortable-hoc';

const SortableItem = SortableElement(({value}) => <li>{value}</li>);

const SortableList = SortableContainer(({items}) => {
  return (
    <ul>
      {items.map((value, index) => (
        <SortableItem key={`item-${index}`} index={index} value={value} />
      ))}
    </ul>
  );
});

angular-drag-and-drop-lists:

<ul dnd-list="list">
  <li ng-repeat="item in list"
      dnd-draggable="item"
      dnd-moved="list.splice($index, 1)"
      dnd-effect-allowed="move"
      dnd-selected="selected = item"
      ng-class="{'selected': selected === item}">
    {{item.name}}
  </li>
</ul>

The code examples showcase the different approaches: react-sortable-hoc uses a component-based structure with HOCs, while angular-drag-and-drop-lists relies on directives and Angular's template syntax.

Component infrastructure and Material Design components for Angular

Pros of Angular Components

  • Comprehensive set of UI components and tools for Angular applications
  • Official Angular library with regular updates and extensive documentation
  • Follows Material Design principles, ensuring consistent and modern UI

Cons of Angular Components

  • Larger package size due to its extensive feature set
  • Steeper learning curve for developers new to Angular or Material Design
  • Less focused on drag-and-drop functionality compared to angular-drag-and-drop-lists

Code Comparison

angular-drag-and-drop-lists:

<ul dnd-list="list">
    <li ng-repeat="item in list"
        dnd-draggable="item"
        dnd-moved="list.splice($index, 1)"
        dnd-effect-allowed="move">
        {{item.label}}
    </li>
</ul>

Angular Components:

<div cdkDropList (cdkDropListDropped)="drop($event)">
  <div *ngFor="let item of items" cdkDrag>{{item}}</div>
</div>

While both libraries provide drag-and-drop functionality, angular-drag-and-drop-lists offers a more specialized solution with additional attributes for fine-tuning behavior. Angular Components provides a more streamlined approach as part of a larger UI component library, integrating seamlessly with other Angular features and Material Design principles.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

angular-drag-and-drop-lists

Angular directives that allow you to build sortable lists with the native HTML5 drag & drop API. The directives can also be nested to bring drag & drop to your WYSIWYG editor, your tree, or whatever fancy structure you are building.

:warning: Discontinuation Notice

This library was built for AngularJS 1.x, which is in maintenance mode. I recommend migrating to Angular and using one of these alternatives:

  • ngx-drag-drop: A fork of this library, re-written for Angular 2 and above.
  • Angular Material Drag & Drop: Lots of features and well supported, although it doesn't seem to support nested lists (bug) and doesn't use the HTML5 Drag & Drop API (which might be a good thing, depending on your use case)
  • ng2-dragula

Let me know if there are other libraries I should add here.

Demo

Supported browsers

Touch devices are not supported, because they do not implement the HTML5 drag & drop standard. However, you can use a shim to make it work on touch devices as well.

Internet Explorer 8 or lower is not supported, but all modern browsers are (see changelog for list of tested browsers).

Download & Installation

  • Download angular-drag-and-drop-lists.js (or the minified version) and include it in your application. If you use bower or npm, just include the angular-drag-and-drop-lists package.
  • Add the dndLists module as a dependency to your angular app.

dnd-draggable directive

Use the dnd-draggable directive to make your element draggable

Attributes

  • dnd-draggable Required attribute. The value has to be an object that represents the data of the element. In case of a drag and drop operation the object will be serialized and unserialized on the receiving end.
  • dnd-effect-allowed Use this attribute to limit the operations that can be performed. Valid options are move, copy and link, as well as all, copyMove, copyLink and linkMove, while move is the default value. The semantics of these operations are up to you and have to be implemented using the callbacks described below. If you allow multiple options, the user can choose between them by using the modifier keys (OS specific). The cursor will be changed accordingly, expect for IE and Edge, where this is not supported. Note that the implementation of this attribute is very buggy in IE9. This attribute works together with dnd-external-sources except on Safari and IE, where the restriction will be lost when dragging accross browser tabs. Design document Demo
  • dnd-type Use this attribute if you have different kinds of items in your application and you want to limit which items can be dropped into which lists. Combine with dnd-allowed-types on the dnd-list(s). This attribute must be a lower case string. Upper case characters can be used, but will be converted to lower case automatically. Demo
  • dnd-disable-if You can use this attribute to dynamically disable the draggability of the element. This is useful if you have certain list items that you don't want to be draggable, or if you want to disable drag & drop completely without having two different code branches (e.g. only allow for admins). Demo

Callbacks

  • dnd-dragstart Callback that is invoked when the element was dragged. The original dragstart event will be provided in the local event variable. Demo
  • dnd-moved Callback that is invoked when the element was moved. Usually you will remove your element from the original list in this callback, since the directive is not doing that for you automatically. The original dragend event will be provided in the local event variable. Demo
  • dnd-copied Same as dnd-moved, just that it is called when the element was copied instead of moved. The original dragend event will be provided in the local event variable. Demo
  • dnd-linked Same as dnd-moved, just that it is called when the element was linked instead of moved. The original dragend event will be provided in the local event variable. Demo
  • dnd-canceled Callback that is invoked if the element was dragged, but the operation was canceled and the element was not dropped. The original dragend event will be provided in the local event variable. Demo
  • dnd-dragend Callback that is invoked when the drag operation ended. Available local variables are event and dropEffect. Demo
  • dnd-selected Callback that is invoked when the element was clicked but not dragged. The original click event will be provided in the local event variable. Demo
  • dnd-callback Custom callback that is passed to dropzone callbacks and can be used to communicate between source and target scopes. The dropzone can pass user defined variables to this callback. This can be used to transfer objects without serialization, see Demo.

CSS classes

  • dndDragging This class will be added to the element while the element is being dragged. It will affect both the element you see while dragging and the source element that stays at it's position. Do not try to hide the source element with this class, because that will abort the drag operation.
  • dndDraggingSource This class will be added to the element after the drag operation was started, meaning it only affects the original element that is still at it's source position, and not the "element" that the user is dragging with his mouse pointer

dnd-list directive

Use the dnd-list attribute to make your list element a dropzone. Usually you will add a single li element as child with the ng-repeat directive. If you don't do that, we will not be able to position the dropped element correctly. If you want your list to be sortable, also add the dnd-draggable directive to your li element(s).

Attributes

  • dnd-list Required attribute. The value has to be the array in which the data of the dropped element should be inserted. The value can be blank if used with a custom dnd-drop handler that handles the insertion on its own.
  • dnd-allowed-types Optional array of allowed item types. When used, only items that had a matching dnd-type attribute will be dropable. Upper case characters will automatically be converted to lower case. Demo
  • dnd-effect-allowed Optional string expression that limits the drop effects that can be performed on the list. See dnd-effect-allowed on dnd-draggable for more details on allowed options. The default value is all.
  • dnd-disable-if Optional boolean expression. When it evaluates to true, no dropping into the list is possible. Note that this also disables rearranging items inside the list. Demo
  • dnd-horizontal-list Optional boolean expression. When it evaluates to true, the positioning algorithm will use the left and right halfs of the list items instead of the upper and lower halfs. Demo
  • dnd-external-sources Optional boolean expression. When it evaluates to true, the list accepts drops from sources outside of the current browser tab, which allows to drag and drop accross different browser tabs. The only major browser for which this is currently not working is Microsoft Edge. Demo

Callbacks

  • dnd-dragover Optional expression that is invoked when an element is dragged over the list. If the expression is set, but does not return true, the element is not allowed to be dropped. The following variables will be available:
    • event The original dragover event sent by the browser.
    • index The position in the list at which the element would be dropped.
    • type The dnd-type set on the dnd-draggable, or undefined if unset. Will be null for drops from external sources in IE and Edge, since we don't know the type in those cases.
    • external Whether the element was dragged from an external source. See dnd-external-sources.
    • dropEffect The dropEffect that is going to be performed, see dnd-effect-allowed.
    • callback If dnd-callback was set on the source element, this is a function reference to the callback. The callback can be invoked with custom variables like this: callback({var1: value1, var2: value2}). The callback will be executed on the scope of the source element. If dnd-external-sources was set and external is true, this callback will not be available.
    • Demo
  • dnd-drop Optional expression that is invoked when an element is dropped on the list. The same variables as for dnd-dragover will be available, with the exception that type is always known and therefore never null. There will also be an item variable, which is the transferred object. The return value determines the further handling of the drop:
    • falsy The drop will be canceled and the element won't be inserted.
    • true Signalises that the drop is allowed, but the dnd-drop callback will take care of inserting the element.
    • Otherwise: All other return values will be treated as the object to insert into the array. In most cases you simply want to return the item parameter, but there are no restrictions on what you can return.
  • dnd-inserted Optional expression that is invoked after a drop if the element was actually inserted into the list. The same local variables as for dnd-drop will be available. Note that for reorderings inside the same list the old element will still be in the list due to the fact that dnd-moved was not called yet. Demo

CSS classes

  • dndPlaceholder When an element is dragged over the list, a new placeholder child element will be added. This element is of type li and has the class dndPlaceholder set. Alternatively, you can define your own placeholder by creating a child element with dndPlaceholder class.
  • dndDragover This class will be added to the list while an element is being dragged over the list.

dnd-nodrag directive

Use the dnd-nodrag attribute inside of dnd-draggable elements to prevent them from starting drag operations. This is especially useful if you want to use input elements inside of dnd-draggable elements or create specific handle elements.

Note: This directive does not work in Internet Explorer 9.

Demo

dnd-handle directive

Use the dnd-handle directive within a dnd-nodrag element in order to allow dragging of that element after all. Therefore, by combining dnd-nodrag and dnd-handle you can allow dnd-draggable elements to only be dragged via specific handle elements.

Note: Internet Explorer will show the handle element as drag image instead of the dnd-draggable element. You can work around this by styling the handle element differently when it is being dragged. Use the CSS selector .dndDragging:not(.dndDraggingSource) [dnd-handle] for that.

Demo

Recommended CSS styles

It is recommended that you apply the following CSS styles:

  • If your application is about moving elements by drag and drop, it is recommended that you hide the source element while dragging, i.e. setting display: none on the .dndDraggingSource class.
  • If your application allows to drop elements into empty lists, you need to ensure that empty lists never have a height or width of zero, e.g. by setting a min-width.
  • You should style the .dndPlaceholder class accordingly.

Note: Previous versions of this directive required postion: relative on certain elements, but this is no longer required.

Why another drag & drop library?

There are tons of other drag & drop libraries out there, but none of them met my three requirements:

  • Angular: If you use angular.js, you really don't want to throw a bunch of jQuery into your app. Instead you want to use libraries that were built the "angular way" and support two-way data binding to update your data model automatically.
  • Nested lists: If you want to build a WYSIWYG editor or have some fancy tree structure, the library has to support nested lists.
  • HTML5 drag & drop: Most drag & drop applications you'll find on the internet use pure JavaScript drag & drop. But with the arrival of HTML5 we can delegate most of the work to the browser. For example: If you want to show the user what they are currently dragging, you'll have to update the position of the element all the time and set it below the mouse pointer. In HTML5 the browser will do that for you! But you can not only save code lines, you can also offer a more native user experience: If you click on an element in a pure JavaScript drag & drop implementation, it will usually start the drag operation. But remember what happens when you click an icon on your desktop: The icon will be selected, not dragged! This is the native behaviour you can bring to your web application with HTML5.

If this doesn't fit your requirements, check out one of the other awesome drag & drop libraries:

  • angular-ui-tree: Very similar to this library, but does not use the HTML5 API. Therefore you need to write some more markup to see what you are dragging and it will create another DOM node that you have to style. However, if you plan to support touch devices this is probably your best choice.
  • angular-dragdrop: One of many libraries with the same name. This one uses the HTML5 API, but if you want to build (nested) sortable lists, you're on your own, because it does not calculate the correct element position for you.
  • more...

License

Copyright (c) 2014 Marcel Juenemann

Copyright (c) 2014-2017 Google Inc.

This is not an official Google product (experimental or otherwise), it is just code that happens to be owned by Google.

MIT License

NPM DownloadsLast 30 Days