All Components

Sortable Overview

The Sortable makes the elements within a list sortable through the drag-and-drop functionality.

Basic Usage

The following example demonstrates the Sortable in action. To sort the items, drag them.

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

@Component({
  selector: 'my-app',
  template: `
    <div class="example-config">
        <h6>Items: {{items | json}}</h6>
    </div>
    <div class="container-fluid">
        <kendo-sortable
            [navigatable]="true"
            [animation] = "true"
            [data]="items"
            class="row"
            itemClass="item col-xs-6 col-sm-3"
            activeItemClass="item col-xs-6 col-sm-3 active"
        >
        </kendo-sortable>
    </div>
  `,
  encapsulation: ViewEncapsulation.None,
  styleUrls: ['styles.css']
})
export class AppComponent {
  public items: string[] = [
    'Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5', 'Item 6', 'Item 7', 'Item 8'
  ];
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SortableModule } from '@progress/kendo-angular-sortable';
import { AppComponent } from './app.component';

@NgModule({
    bootstrap:    [AppComponent],
    declarations: [AppComponent],
    imports:      [BrowserModule, BrowserAnimationsModule, SortableModule]
})
export class AppModule {}
.item {
    background-color: #bfe7f9;
    color: #1494d0;
    border: 1px solid #fff;
    height: 70px;
    line-height: 68px;
    font-size: 16px;
    text-align: center;
    outline: none;
    cursor: move;
}

.item:hover,
.employee:hover {
    opacity: 0.8;
}

.item.active,
.employee.active {
    background-color: #27aceb;
    color: #fff;
    border-color: #27aceb;
    z-index: 10;
}

.item.disabled {
    opacity: 0.5;
    cursor: default;
}

.team {
    min-height: 240px;
    padding-top: 15px;
    padding-bottom: 15px;
    border: 1px solid #fff;
    background-color: #dff3fc;
}

.team-b {
    background-color: #fbe0e7;
}

.employee {
    background-color: #bfe7f9;
    color: #1494d0;
    margin: 1px;
    padding: 5px;
    cursor: move;
}

.team-b .employee {
    background-color: #f3b9c9;
    color: #dd4672;
}

.team-b .employee.active {
    background-color: #dd4672;
    color: #fff;
}

.empty {
    height: 150px;
}
import { AppModule } from './app.module';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

Installation

  1. The Sortable package is published on the Progress NPM Registry. To set up your access, follow the steps in Installation.

  2. Download and install the package:

    npm install --save @progress/kendo-angular-sortable @progress/kendo-angular-l10n
  3. Once installed, import the SortableModule in your application root module:

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { SortableModule } from '@progress/kendo-angular-sortable';
    import { AppComponent } from './app.component';
    
    @NgModule({
       bootstrap:    [AppComponent],
       declarations: [AppComponent],
       imports:      [BrowserModule, SortableModule]
    })
    export class AppModule {
    }

Dependencies

The Sortable package requires the following peer dependencies that have to be installed by your application:

  • @angular/common
  • @angular/core
  • @progress/kendo-angular-l10n

Features

The Sortable delivers the following features:

Disabled Items

You can disable items by using the disabledIndexes property.

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

@Component({
  selector: 'my-app',
  template: `
    <div class="example-config">
        <h5>Items: {{items | json}}</h5>
        <h5>Disabled items: {{disabledIndexes}}</h5>
    </div>
    <div class="container-fluid">
        <kendo-sortable
            [data]="items"
            [navigatable]="true"
            [animation]="true"
            [disabledIndexes]="disabledIndexes"
            class="row"
            itemClass="item col-xs-6 col-sm-3"
            activeItemClass="item col-xs-6 col-sm-3 active"
            disabledItemClass="item col-xs-6 col-sm-3 disabled">
        >
        </kendo-sortable>
    </div>
  `,
  styleUrls: ['styles.css'],
  encapsulation: ViewEncapsulation.None
})
export class AppComponent {
  public disabledIndexes: number[]=[0, 2, 5, 7];
  public items: string[]=[];
  constructor() {
      for (let i=0; i < 8; i++) {
          this.items[i]="Item " + i;
      }
  }
}

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SortableModule } from '@progress/kendo-angular-sortable';
import { AppComponent } from './app.component';

@NgModule({
    bootstrap:    [AppComponent],
    declarations: [AppComponent],
    imports:      [BrowserModule, BrowserAnimationsModule, SortableModule]
})
export class AppModule {}
.item {
    background-color: #bfe7f9;
    color: #1494d0;
    border: 1px solid #fff;
    height: 70px;
    line-height: 68px;
    font-size: 16px;
    text-align: center;
    outline: none;
    cursor: move;
}

.item:hover,
.employee:hover {
    opacity: 0.8;
}

.item.active,
.employee.active {
    background-color: #27aceb;
    color: #fff;
    border-color: #27aceb;
    z-index: 10;
}

.item.disabled {
    opacity: 0.5;
    cursor: default;
}

.team {
    min-height: 240px;
    padding-top: 15px;
    padding-bottom: 15px;
    border: 1px solid #fff;
    background-color: #dff3fc;
}

.team-b {
    background-color: #fbe0e7;
}

.employee {
    background-color: #bfe7f9;
    color: #1494d0;
    margin: 1px;
    padding: 5px;
    cursor: move;
}

.team-b .employee {
    background-color: #f3b9c9;
    color: #dd4672;
}

.team-b .employee.active {
    background-color: #dd4672;
    color: #fff;
}

.empty {
    height: 150px;
}
import { AppModule } from './app.module';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

Transfer of Items

By using drag zones, the Sortable enables you to transfer items between different Sortable components. To achieve this behavior, configure the zone and acceptZones properties.

You can transfer items by dragging them between two or more lists.

When dragged from the source to the target Sortable component, the currently active item is hidden in the original one through the visible:false and display:none inline styles. While dragging takes place, the item is removed from the original (source) component on dragEnd (mouse up) and added to the second (target) component on dragOver. As a result, between the dragEnd and the dragOver actions, two identical items simultaneously exist in both the source and the target Sortable components.

The following example demonstrates how to enable the dragging of items between different items list.

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

@Component({
    selector: 'my-app',
    template: `
    <div class="example-config">
            <h5>Team A: {{palettes.TeamA | json}}</h5>
            <h5>Team B: {{palettes.TeamB | json}}</h5>
    </div>
    <div class="container-fluid">
        <div class="row">
            <div class="col-xs-12 col-sm-6 team">
                <h5>Team A</h5>
                <kendo-sortable [data]="palettes.TeamA"
                    zone="twoWay"
                    emptyText="Move employees from Team B to Team A."
                    class="row"
                    itemClass="employee"
                    [emptyItemStyle]="{'min-height': '150px', width:'100%'}"
                    emptyItemClass="empty"
                    activeItemClass="employee active">
                </kendo-sortable>
            </div>
            <div class="col-xs-12 col-sm-6 team team-b">
                <h5>Team B</h5>
                <kendo-sortable [data]="palettes.TeamB"
                    zone="twoWay"
                    emptyText="Move employees from Team A to Team B."
                    class="row"
                    itemClass="employee"
                    [emptyItemStyle]="{'min-height': '150px', width:'100%'}"
                    emptyItemClass="empty"
                    activeItemClass="employee active">
                </kendo-sortable>
            </div>
        </div>
    </div>
`,
    styleUrls: ['styles.css'],
    encapsulation: ViewEncapsulation.None
})
export class AppComponent {
    public palettes: any=this.palettes={
        "TeamA": ['Peter Franken', 'Simon Crowther', 'Catherine Dewey'],
        "TeamB": ['Lino Rodriguez', 'Paolo Accorti']
    };
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SortableModule } from '@progress/kendo-angular-sortable';
import { AppComponent } from './app.component';

@NgModule({
    bootstrap:    [AppComponent],
    declarations: [AppComponent],
    imports:      [BrowserModule, BrowserAnimationsModule, SortableModule]
})
export class AppModule {}
.item {
    background-color: #bfe7f9;
    color: #1494d0;
    border: 1px solid #fff;
    height: 70px;
    line-height: 68px;
    font-size: 16px;
    text-align: center;
    outline: none;
    cursor: move;
}

.item:hover,
.employee:hover {
    opacity: 0.8;
}

.item.active,
.employee.active {
    background-color: #27aceb;
    color: #fff;
    border-color: #27aceb;
    z-index: 10;
}

.item.disabled {
    opacity: 0.5;
    cursor: default;
}

.team {
    min-height: 240px;
    padding-top: 15px;
    padding-bottom: 15px;
    border: 1px solid #fff;
    background-color: #dff3fc;
}

.team-b {
    background-color: #fbe0e7;
}

.employee {
    background-color: #bfe7f9;
    color: #1494d0;
    margin: 1px;
    padding: 5px;
    cursor: move;
}

.team-b .employee {
    background-color: #f3b9c9;
    color: #dd4672;
}

.team-b .employee.active {
    background-color: #dd4672;
    color: #fff;
}

.empty {
    height: 150px;
}
import { AppModule } from './app.module';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

Events

The following example demonstrates basic events of the Sortable component.

import { Component, ViewEncapsulation } from '@angular/core';
import { DataEvent, DragDropEvent } from '@progress/kendo-angular-sortable';

@Component({
  selector: 'my-app',
  template: `
    <div class="container-fluid" *ngFor="let group of items; let i = index">
        <kendo-sortable
            zone="default"
            [navigatable]="true"
            [animation] = "true"
            [data]="items[i]"
            class="row"
            itemClass="item col-xs-6 col-sm-3"
            activeItemClass="item col-xs-6 col-sm-3 active"
            (dataAdd)="onDataAdd(i, $event)"
            (dataRemove)="onDataRemove(i, $event)"
            (dragEnd)="onDragEnd(i, $event)"
            (dragOver)="onDragOver(i, $event)"
            (dragStart)="onDragStart(i, $event)"
        >
        </kendo-sortable>
        <event-log title="Event log" [events]="events[i]">
        </event-log>
    </div>
  `,
  encapsulation: ViewEncapsulation.None,
  styleUrls: ['styles.css']
})
export class AppComponent {
  public items: string[][] = [
    ['Item 1', 'Item 2', 'Item 3', 'Item 4'],
    ['Item 5', 'Item 6', 'Item 7', 'Item 8']
  ];

  public events: string[][] = [[], []];

  public onDataAdd(src: number, e: DataEvent): void {
    this.log(src, 'dataAdd', e.index);
  }

  public onDataRemove(src: number, e: DataEvent): void {
    this.log(src, 'dataRemove', e.index);
  }

  public onDragEnd(src: number, e: DragDropEvent): void {
    this.log(src, 'dragEnd', e.index);
  }

  public onDragOver(src: number, e: DragDropEvent): void {
    // Not logging due to the large number of events
  }

  public onDragStart(src: number, e: DragDropEvent): void {
    this.log(src, 'dragStart', e.index);
  }

  private log(src: number, event: string, itemIndex: number): void {
    this.events[src].push(`${event} - ${this.items[src][itemIndex]}`);
  }
}

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SortableModule } from '@progress/kendo-angular-sortable';
import { AppComponent } from './app.component';
import { EventLogComponent } from './event-log.component';

@NgModule({
    bootstrap:    [AppComponent],
    declarations: [AppComponent, EventLogComponent],
    imports:      [BrowserModule, BrowserAnimationsModule, SortableModule]
})
export class AppModule {}

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

@Component({
  selector: 'event-log',
  template: `
    <div class="example-config">
      <h5>{{ title }}</h5>
      <ul class="event-log">
        <li *ngFor="let event of events.reverse()">{{ event }}</li>
      </ul>
    </div>
  `
})
export class EventLogComponent {
  @Input() title: string;
  @Input() events: string[];
}

.item {
    background-color: #bfe7f9;
    color: #1494d0;
    border: 1px solid #fff;
    height: 70px;
    line-height: 68px;
    font-size: 16px;
    text-align: center;
    outline: none;
    cursor: move;
}

.item:hover,
.employee:hover {
    opacity: 0.8;
}

.item.active,
.employee.active {
    background-color: #27aceb;
    color: #fff;
    border-color: #27aceb;
    z-index: 10;
}

.item.disabled {
    opacity: 0.5;
    cursor: default;
}

.team {
    min-height: 240px;
    padding-top: 15px;
    padding-bottom: 15px;
    border: 1px solid #fff;
    background-color: #dff3fc;
}

.team-b {
    background-color: #fbe0e7;
}

.employee {
    background-color: #bfe7f9;
    color: #1494d0;
    margin: 1px;
    padding: 5px;
    cursor: move;
}

.team-b .employee {
    background-color: #f3b9c9;
    color: #dd4672;
}

.team-b .employee.active {
    background-color: #dd4672;
    color: #fff;
}

.empty {
    height: 150px;
}
import { AppModule } from './app.module';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);
In this article