The sortable component represents a list of items, with ability to sort them or move to another container via drag&drop. Input collection isn't mutated by the component, so events ngModelChange
, onChange
are using new collections.
The easiest way to add the sortable component to your app (will be added to the root module)
Basic
Windstorm
Bombasto
Magneta
Tornado
Mr. O
Tomato
model: [ "Windstorm", "Bombasto", "Magneta", "Tornado" ]
model: [ "Mr. O", "Tomato" ]
<div class="row"> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <bs-sortable [(ngModel)]="itemStringsLeft" itemClass="sortable-item" itemActiveClass="sortable-item-active" placeholderItem="Drag here" placeholderClass="placeholderStyle text-center" wrapperClass="sortable-wrapper" ></bs-sortable> </div> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <bs-sortable [(ngModel)]="itemStringsRight" itemClass="sortable-item" itemActiveClass="sortable-item-active" placeholderItem="Drag here" placeholderClass="placeholderStyle text-center" wrapperClass="sortable-wrapper" ></bs-sortable> </div> </div> <div class='row'> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <pre class="code-preview">model: {{ itemStringsLeft | json }}</pre> </div> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <pre class="code-preview">model: {{ itemStringsRight | json }}</pre> </div> </div>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'basic-demo', templateUrl: './basic.component.html', standalone: false }) export class DemoBasicComponent { itemStringsLeft = [ 'Windstorm', 'Bombasto', 'Magneta', 'Tornado' ]; itemStringsRight = ['Mr. O', 'Tomato']; }
Complex data model
Windstorm
Bombasto
Magneta
Tornado
Mr. O
Tomato
model: [ { "id": 1, "name": "Windstorm" }, { "id": 2, "name": "Bombasto" }, { "id": 3, "name": "Magneta" } ]
model: [ { "id": 4, "name": "Tornado" }, { "id": 5, "name": "Mr. O" }, { "id": 6, "name": "Tomato" } ]
<div class="row"> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <bs-sortable [(ngModel)]="itemObjectsLeft" fieldName="name" itemClass="sortable-item" itemActiveClass="sortable-item-active" placeholderItem="Drag here" placeholderClass="placeholderStyle text-center" wrapperClass="sortable-wrapper" ></bs-sortable> </div> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <bs-sortable [(ngModel)]="itemObjectsRight" fieldName="name" itemClass="sortable-item" itemActiveClass="sortable-item-active" placeholderItem="Drag here" placeholderClass="placeholderStyle text-center" wrapperClass="sortable-wrapper" ></bs-sortable> </div> </div> <div class='row'> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <pre class="code-preview">model: {{ itemObjectsLeft | json }}</pre> </div> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <pre class="code-preview">model: {{ itemObjectsRight | json }}</pre> </div> </div>
import { Component } from '@angular/core'; interface IItemObject { id: number; name: string; } @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'complex-datamodel-demo', templateUrl: './complex-datamodel.component.html', standalone: false }) export class ComplexDatamodelDemoComponent { itemObjectsLeft: IItemObject[] = [ { id: 1, name: 'Windstorm' }, { id: 2, name: 'Bombasto' }, { id: 3, name: 'Magneta' } ]; itemObjectsRight: IItemObject[] = [ { id: 4, name: 'Tornado' }, { id: 5, name: 'Mr. O' }, { id: 6, name: 'Tomato' } ]; }
Custom item template
0: Windstorm
1: Bombasto
2: Magneta
3: Tornado
Mr. O
Tomato
model: [ "Mr. O", "Tomato" ]
model: [ "Mr. O", "Tomato" ]
<ng-template #itemTemplate let-item="item" let-index="index"><span>{{index}}: {{item.value}}</span></ng-template> <div class="row"> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <bs-sortable [(ngModel)]="itemStringsLeft" [itemTemplate]="itemTemplate" itemClass="sortable-item" itemActiveClass="sortable-item-active" placeholderItem="Drag here" placeholderClass="placeholderStyle text-center" wrapperClass="sortable-wrapper" ></bs-sortable> </div> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <bs-sortable [(ngModel)]="itemStringsRight" itemClass="sortable-item" itemActiveClass="sortable-item-active" placeholderItem="Drag here" placeholderClass="placeholderStyle text-center" wrapperClass="sortable-wrapper" ></bs-sortable> </div> </div> <div class='row'> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <pre class="code-preview">model: {{ itemStringsRight | json }}</pre> </div> <div class="col-xs-6 col-6 col-md-5 col-lg-3"> <pre class="code-preview">model: {{ itemStringsRight | json }}</pre> </div> </div>
import { Component } from '@angular/core'; @Component({ // eslint-disable-next-line @angular-eslint/component-selector selector: 'custom-item-template-demo', templateUrl: './custom-item-template.html', standalone: false }) export class CustomItemTemplateDemoComponent { itemStringsLeft: string[] = [ 'Windstorm', 'Bombasto', 'Magneta', 'Tornado' ]; itemStringsRight: string[] = ['Mr. O', 'Tomato']; }
Accessibility
You can use aria-dropeffect="..."
and aria-grabbed
for .sortable-item
. When you start drag item aria-grabbed
must have true
state. aria-dropeffect
property is defined depending on the grabbed object.
But be careful, these attributes are deprecated
.
Installation
ng add ngx-bootstrap --component sortable
### Standalone component usage import { SortableModule } from 'ngx-bootstrap/sortable'; @Component({ standalone: true, imports: [SortableModule,...] }) export class AppComponent(){} ### Module usage import { SortableModule } from 'ngx-bootstrap/sortable'; @NgModule({ imports: [SortableModule,...] }) export class AppModule(){}
Basic
Windstorm
Bombasto
Magneta
Tornado
Mr. O
Tomato
model: [ "Windstorm", "Bombasto", "Magneta", "Tornado" ]
model: [ "Mr. O", "Tomato" ]
Complex data model
Windstorm
Bombasto
Magneta
Tornado
Mr. O
Tomato
model: [ { "id": 1, "name": "Windstorm" }, { "id": 2, "name": "Bombasto" }, { "id": 3, "name": "Magneta" } ]
model: [ { "id": 4, "name": "Tornado" }, { "id": 5, "name": "Mr. O" }, { "id": 6, "name": "Tomato" } ]
Custom item template
0: Windstorm
1: Bombasto
2: Magneta
3: Tornado
Mr. O
Tomato
model: [ "Mr. O", "Tomato" ]
model: [ "Mr. O", "Tomato" ]