Gathering detailed insights and metrics for angular-sortablejs
Gathering detailed insights and metrics for angular-sortablejs
Gathering detailed insights and metrics for angular-sortablejs
Gathering detailed insights and metrics for angular-sortablejs
sortablejs
JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery required. Supports Meteor, AngularJS, React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap.
@worktile/ngx-sortablejs
nxt-sortablejs
Angular sortablejs bindings.
angular-legacy-sortablejs-maintained
Angular (legacy) directive for SortableJS.
Angular 2+ binding to SortableJS. Previously known as angular-sortablejs
npm install angular-sortablejs
Typescript
Module System
Node Version
NPM Version
TypeScript (66.3%)
HTML (26.59%)
JavaScript (6.74%)
CSS (0.19%)
SCSS (0.18%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
469 Stars
223 Commits
160 Forks
11 Watchers
34 Branches
21 Contributors
Updated on Jun 05, 2025
Latest Version
2.7.0
Package Id
angular-sortablejs@2.7.0
Unpacked Size
44.35 kB
Size
11.46 kB
File Count
38
NPM Version
6.8.0
Node Version
10.14.1
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
This package is an Angular 2+ binding for Sortable.js. Supports standard arrays and Angular FormArray
.
See the library in action in a demo project (based on the Angular CLI). The source code for all the examples could be found here.
Trees are also supported: tree with fake root element (*ngFor once, root can also be hidden anyway) or without (*ngFor 2 times).
1npm i sortablejs angular-sortablejs
You are configured now. If you use Webpack or Angular CLI go to the usage. If you have SystemJS, that's sad, but you can go to the end of the document to find configuration steps there.
First, import SortablejsModule.forRoot({ /* and here some global settings if needed */ })
into the root module of your application:
1imports: [ 2 // ... 3 SortablejsModule.forRoot({ animation: 150 }), 4 // ... 5]
Then import SortablejsModule
into the other angular modules where you want to use it:
1imports: [ 2 // ... 3 SortablejsModule, 4 // ... 5]
Then use sortablejs
property on a container HTML element to tell Angular that this is a sortable container; also pass the items
array to both *ngFor
and [sortablejs]
to register the changes automatically.
1import { Component } from '@angular/core'; 2 3@Component({ 4 selector: 'my-app', 5 template: ` 6 <h2>Drag / drop the item</h2> 7 <div [sortablejs]="items"> 8 <div *ngFor="let item of items">{{ item }}</div> 9 </div> 10 ` 11}) 12export class AppComponent { 13 items = [1, 2, 3, 4, 5]; 14}
Pass the options with sortablejsOptions
property.
1import { Component } from '@angular/core'; 2 3@Component({ 4 selector: 'my-app', 5 template: ` 6 <h2>Drag / drop the item</h2> 7 <div [sortablejs]="items" [sortablejsOptions]="{ animation: 150 }"> 8 <div *ngFor="let item of items">{{ item }}</div> 9 </div> 10 ` 11}) 12export class AppComponent { 13 items = [1, 2, 3, 4, 5]; 14}
You can use the options' onUpdate
method to track the changes (see also Passing the options section):
1constructor() { 2 this.options = { 3 onUpdate: (event: any) => { 4 this.postChangesToServer(); 5 } 6 }; 7}
If you use FormArray you are able to choose a more elegant solution:
1public items = new FormArray([ 2 new FormControl(1), 3 new FormControl(2), 4 new FormControl(3), 5]); 6 7constructor() { 8 this.items.valueChanges.subscribe(() => { 9 this.postChangesToServer(this.items.value); 10 }); 11}
but note, that here you will be able to take the whole changed array only (no oldIndex / newIndex).
You can pass a new options object at anytime via the [sortablejsOptions]
binding and the Angular's change detection will check for the changes from the previous options and will call the low level option setter from Sortable.js to set the new option values.
Note: It will only detect changes when a brand new options object is passed, not deep changes.
The only thing which should be done is assigning the group
option to the both list. Everything else is handled automatically.
1import { Component } from '@angular/core'; 2import { SortablejsOptions } from 'angular-sortablejs'; 3 4@Component({ 5 selector: 'my-app', 6 template: ` 7 <h2>Drag / drop the item</h2> 8 <h3>list 1</h3> 9 <div class="items1" [sortablejs]="items1" [sortablejsOptions]="options"> 10 <div *ngFor="let item of items1">{{ item }}</div> 11 </div> 12 <h3>list 2</h3> 13 <div class="items2" [sortablejs]="items2" [sortablejsOptions]="options"> 14 <div *ngFor="let item of items2">{{ item }}</div> 15 </div> 16 ` 17}) 18export class AppComponent { 19 items1 = [1, 2, 3, 4, 5]; 20 items2 = ['a', 'b', 'c', 'd', 'e']; 21 22 options: SortablejsOptions = { 23 group: 'test' 24 }; 25}
The clone mode is similar to the one above (of course the proper Sortablejs settings should be used; see demo). The only important thing is that the angular-sortablejs
does clone the HTML element but does not clone the variable (or FormControl
in case of FormArray
input). By default the variable will be taken as is: a primitive will be copied, an object will be referenced.
If you want to clone the item being sorted in a different manner, you can provide sortablejsCloneFunction
as a parameter. This function receives an item and should return a clone of that item.
1import { Component } from '@angular/core'; 2import { SortablejsOptions } from 'angular-sortablejs'; 3 4@Component({ 5 selector: 'my-app', 6 template: ` 7 <h2>Drag / drop the item</h2> 8 <h3>list 1</h3> 9 <div class="items1" [sortablejs]="items1" [sortablejsOptions]="options" [sortablejsCloneFunction]="myCloneImplementation"> 10 <div *ngFor="let item of items1">{{ item }}</div> 11 </div> 12 <h3>list 2</h3> 13 <div class="items2" [sortablejs]="items2" [sortablejsOptions]="options" [sortablejsCloneFunction]="myCloneImplementation"> 14 <div *ngFor="let item of items2">{{ item }}</div> 15 </div> 16 ` 17}) 18export class AppComponent { 19 20 myCloneImplementation = (item) => { 21 return item; // this is what happens if sortablejsCloneFunction is not provided. Add your stuff here 22 } 23 24}
By default, the boolean parameter runInsideAngular is set to false. This means that the initial binding of all mouse events of the component will be set so that they will not trigger Angular's change detection.
If this parameter is set to true, then for large components - with a lot of data bindings - the UI will function in a staggered and lagging way (mainly when dragging items), while every event will trigger the change detection (which might be needed in some special edge cases).
If you want to use the same sortable options across different places of your application you might want to set up global configuration. Add the following to your main module to enable e.g. animation: 150
everywhere:
1imports: [ 2 // ... 3 // any properties and events available on original library work here as well 4 SortablejsModule.forRoot({ 5 animation: 150 6 }), 7 // ... 8]
This value will be used as a default one, but it can be overwritten by a local sortablejsOptions
property.
The elements with ripple effect like mat-list-item
are affected. The dragging is broken because there is a div created right under the cursor and the webkit has no idea what to do with it.
There are two solutions:
1<a mat-list-item [disableRipple]="true">
handle
property and block propagation of mousedown
and touchstart
events on the handler to prevent ripple.1<div [sortablejs]="..." [sortablejsOptions]="{ handle: '.handle' }"> 2 <a mat-list-item *ngFor="let a of b" [routerLink]="..." routerLinkActive="active"> 3 <mat-icon matListIcon 4 class="handle" 5 (mousedown)="$event.stopPropagation()" 6 (touchstart)="$event.stopPropagation()">drag_handle</mat-icon> {{ a }} 7 </a> 8</div>
The model is automatically updated because you pass the items
as <div [sortablejs]="items">
. The items
variable can be either an ordinary JavaScript array or a reactive forms FormArray
.
If you won't pass anything, e.g. <div sortablejs>
, the items won't be automatically updated, thus you should take care of updating the array on your own using standard Sortable.js
events.
Original events onAdd
, onRemove
, onUpdate
are intercepted by the library in order to reflect the sortable changes into the data. If you will add your own event handlers (inside of the options object) they will be called right after the data binding is done. If you don't pass the data, e.g. <div sortablejs>
the data binding is skipped and only your event handlers will be fired.
Important: the original onAdd
event happens before the onRemove
event because the original library makes it like that. We change this behavior and call 'onAdd' after the 'onRemove'. If you want to work with original onAdd event you can use onAddOriginal
which happens before onRemove
.
IMPORTANT: Follow this only if you have SystemJS. If you have no errors without this step - most likely you don't need it!
Adapt your systemjs.config.js
(or another place where you configure SystemJS) file with the following:
1// ... 2var map = { 3 // ... 4 'angular-sortablejs': 'node_modules/angular-sortablejs/dist/', 5 'sortablejs/Sortable.min': 'node_modules/sortablejs/Sortable.min.js', 6 // ... 7}; 8// ... 9var packages = { 10 // ... 11 'angular-sortablejs': { main: 'index.js', defaultExtension: 'js' }, 12 // ... 13}; 14// ... 15var config = { 16 map: map, 17 packages: packages 18}; 19 20System.config(config);
This is important to let SystemJS know everything it needs about the dependencies it needs to load.
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
Found 2/24 approved changesets -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
Reason
132 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-07-14
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More