{"id":13527930,"url":"https://github.com/angular-ui/ui-sortable","last_synced_at":"2025-04-01T11:30:31.838Z","repository":{"id":7124841,"uuid":"8419846","full_name":"angular-ui/ui-sortable","owner":"angular-ui","description":"jQuery UI Sortable for AngularJS","archived":true,"fork":false,"pushed_at":"2018-10-24T14:21:55.000Z","size":1671,"stargazers_count":1261,"open_issues_count":40,"forks_count":443,"subscribers_count":51,"default_branch":"master","last_synced_at":"2024-10-29T15:29:33.162Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://angular-ui.github.io/ui-sortable/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/angular-ui.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-02-25T22:34:53.000Z","updated_at":"2024-08-29T05:44:39.000Z","dependencies_parsed_at":"2022-09-10T20:00:12.529Z","dependency_job_id":null,"html_url":"https://github.com/angular-ui/ui-sortable","commit_stats":null,"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angular-ui%2Fui-sortable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angular-ui%2Fui-sortable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angular-ui%2Fui-sortable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angular-ui%2Fui-sortable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/angular-ui","download_url":"https://codeload.github.com/angular-ui/ui-sortable/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246631485,"owners_count":20808687,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T06:02:07.008Z","updated_at":"2025-04-01T11:30:31.484Z","avatar_url":"https://github.com/angular-ui.png","language":"JavaScript","readme":"# UI.Sortable directive\n[![npm](https://img.shields.io/npm/v/angular-ui-sortable.svg)](https://www.npmjs.com/package/angular-ui-sortable)\n[![npm](https://img.shields.io/npm/dm/angular-ui-sortable.svg)](https://www.npmjs.com/package/angular-ui-sortable)\n[![Build Status](https://travis-ci.org/angular-ui/ui-sortable.svg?branch=master)](https://travis-ci.org/angular-ui/ui-sortable)\n[![Coverage Status](https://coveralls.io/repos/angular-ui/ui-sortable/badge.svg?branch=master)](https://coveralls.io/r/angular-ui/ui-sortable?branch=master)\n[![debugInfoEnabled(false) Ready Badge](https://rawgit.com/thgreasi/ng-debugInfoDisabled-badges/master/badge1.svg)](https://docs.angularjs.org/guide/production#disabling-debug-data)\n[![Join the chat at https://gitter.im/angular-ui/ui-sortable](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/angular-ui/ui-sortable?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\nThis directive allows you to sort an array with drag \u0026 drop.\n\n## Requirements\n\n- JQuery v3.1+ (for jQuery v1.x \u0026 v2.x use [v0.14.x versions](https://github.com/angular-ui/ui-sortable/tree/v0.14.x-stable))\n- JQueryUI v1.12+\n- AngularJS v1.2+\n\n[Single minified cdn link](http://cdn.jsdelivr.net/g/jquery@1,jquery.ui@1.10%28jquery.ui.core.min.js+jquery.ui.widget.min.js+jquery.ui.mouse.min.js+jquery.ui.sortable.min.js%29,angularjs@1.2,angular.ui-sortable) ~245kB and [example](http://codepen.io/thgreasi/pen/olDJi) with JQuery v1.x, required parts of JQueryUI v1.10, AngularJS v1.2 \u0026 latest angular-ui-sortable.\n\n**Notes:**\n\u003e * JQuery must be included before AngularJS.  \n\u003e * JQueryUI dependecies include [widget](http://api.jqueryui.com/jQuery.widget/), [data](http://api.jqueryui.com/data-selector/), [scroll-parent](http://api.jqueryui.com/scrollParent/), [mouse](http://api.jqueryui.com/mouse/) \u0026 [sortable](http://api.jqueryui.com/sortable/). Creating a [custom build](http://jqueryui.com/download/#!version=1.12.1\u0026components=101000000100000010000000010000000000000000000000) will [greatly reduce](https://github.com/angular-ui/ui-sortable/issues/154#issuecomment-40279430) the required file size. ([CDN](http://www.jsdelivr.com/) links for comparison: [full](https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js) vs  [minimal](https://cdn.jsdelivr.net/combine/npm/jquery-ui@1.12/ui/version.min.js,npm/jquery-ui@1.12/ui/widget.min.js,npm/jquery-ui@1.12/ui/data.min.js,npm/jquery-ui@1.12/ui/scroll-parent.min.js,npm/jquery-ui@1.12/ui/widgets/mouse.min.js,npm/jquery-ui@1.12/ui/widgets/sortable.min.js))\n\u003e * Users of AngularJS pre v1.2 can use [v0.10.x](https://github.com/angular-ui/ui-sortable/tree/v0.10.x-stable) or [v0.12.x](https://github.com/angular-ui/ui-sortable/tree/v0.12.x-stable) branches.\n\u003e * Early adopters of [Angular2](https://angular.io/) can use the  [ng2 branch](https://github.com/angular-ui/ui-sortable/tree/ng2).\n\n## Installation\n\n* Install with Bower `bower install -S angular-ui-sortable`\n* Install with npm `npm install -S angular-ui-sortable`\n* Download one of the [Releases](https://github.com/angular-ui/ui-sortable/releases) or the [latest Master branch](https://github.com/angular-ui/ui-sortable/archive/master.zip)\n\n## Usage\n\nLoad the script file: sortable.js in your application:\n\n```html\n\u003cscript type=\"text/javascript\" src=\"modules/directives/sortable/src/sortable.js\"\u003e\u003c/script\u003e\n```\n\nAdd the sortable module as a dependency to your application module:\n\n```js\nvar myAppModule = angular.module('MyApp', ['ui.sortable'])\n```\n\nApply the directive to your form elements:\n\n```html\n\u003cul ui-sortable ng-model=\"items\"\u003e\n  \u003cli ng-repeat=\"item in items\"\u003e{{ item }}\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n**Developing Notes:**\n\n* `ng-model` is required, so that the directive knows which model to update.\n* `ui-sortable` element should contain only one `ng-repeat`, but other non-repeater elements above or below may still exist.\n  Otherwise the index matching of the `ng-model`'s items and the DOM elements generated by the `ng-repeat` will break.  \n  **In other words: The items of `ng-model` must match the indexes of the DOM elements generated by the `ng-repeat`.**\n* [`Filters`](https://docs.angularjs.org/guide/filter) that manipulate the model (like [filter](https://docs.angularjs.org/api/ng/filter/filter), [orderBy](https://docs.angularjs.org/api/ng/filter/orderBy), [limitTo](https://docs.angularjs.org/api/ng/filter/limitTo),...) should be applied in the `controller` instead of the `ng-repeat` (refer to [the provided examples](#examples)).  \nThis is the preferred way since it:\n  - is performance wise better\n  - reduces the chance of code duplication\n  - [is suggested by the angularJS team](https://www.youtube.com/watch?feature=player_detailpage\u0026v=ZhfUv0spHCY#t=3048)\n  - it does not break the matching of the generated DOM elements and the `ng-model`'s items\n* `ui-sortable` lists containing many 'types' of items can be implemented by using dynamic template loading [with ng-include](http://stackoverflow.com/questions/14607879/angularjs-load-dynamic-template-html-within-directive/14621927#14621927) or a [loader directive](https://github.com/thgreasi/tg-dynamic-directive), to determine how each model item should be rendered. Also take a look at the [Tree with dynamic template](http://codepen.io/thgreasi/pen/QKmWKj) example.\n\n### Options\n\nAll the [jQueryUI Sortable options](http://api.jqueryui.com/sortable/) can be passed through the directive.  \nAdditionally, the `ui` argument of the available callbacks gets enriched with some extra properties as specified to the [API.md file](API.md#uiitemsortable-api-documentation).\nAny model changes that happen inside the available callbacks, are applied right after the stop event. We are not wrapping callbacks like `start`/`change`/... with `$apply`, in order to minimize the number of digest loops and avoid possible modifications of the model (eg: by watchers) before the drop takes place.\n\n```js\nmyAppModule.controller('MyController', function($scope) {\n  $scope.items = [\"One\", \"Two\", \"Three\"];\n\n  $scope.sortableOptions = {\n    update: function(e, ui) { ... },\n    axis: 'x'\n  };\n});\n```\n\n```html\n\u003cul ui-sortable=\"sortableOptions\" ng-model=\"items\"\u003e\n  \u003cli ng-repeat=\"item in items\"\u003e{{ item }}\u003c/li\u003e\n\u003c/ul\u003e\n```\n\nWhen using event callbacks ([start](http://api.jqueryui.com/sortable/#event-start)/[update](http://api.jqueryui.com/sortable/#event-update)/[stop](http://api.jqueryui.com/sortable/#event-stop)...), avoid manipulating DOM elements (especially the one with the ng-repeat attached).\nThe suggested pattern is to use callbacks for emmiting events and altering the scope (inside the 'Angular world').\n\n#### ui-floating\n\n**ui-floating** (default: undefined)  \nDescription: Enables a workaround for smooth horizontal sorting.  \nType: [Boolean](http://api.jquery.com/Types/#Boolean)/[String](http://api.jquery.com/Types/#String)/`undefined`\n*   **undefined**: Relies on jquery.ui to detect the list's orientation.\n*   **false**:     Forces jquery.ui.sortable to detect the list as vertical.\n*   **true**:      Forces jquery.ui.sortable to detect the list as horizontal.\n*   **\"auto\"**:    Detects on each drag `start` if the element is floating or not.\n\nTo have a smooth horizontal-list reordering, jquery.ui.sortable needs to detect the orientation of the list.\nThis detection takes place during the initialization of the plugin (and some of the checks include: whether the first item is floating left/right or if 'axis' parameter is 'x', etc).\nThere is also a [known issue](https://bugs.jqueryui.com/ticket/7498) about initially empty horizontal lists.\n\nTo provide a solution/workaround (till jquery.ui.sortable.refresh() also tests the orientation or a more appropriate method is provided), ui-sortable directive provides a `ui-floating` option as an extra to the [jquery.ui.sortable options](http://api.jqueryui.com/sortable/).\n\n```html\n\u003cul ui-sortable=\"{ 'ui-floating': true }\" ng-model=\"items\"\u003e\n  \u003cli ng-repeat=\"item in items\"\u003e{{ item }}\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n**OR**\n\n```js\n$scope.sortableOptions = {\n  'ui-floating': true\n};\n```\n```html\n\u003cul ui-sortable=\"sortableOptions\" ng-model=\"items\"\u003e\n  \u003cli ng-repeat=\"item in items\"\u003e{{ item }}\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n\n#### ui-model-items\n\n**ui-model-items** (default: `\u003e [ng-repeat],\u003e [data-ng-repeat],\u003e [x-ng-repeat]`)  \nDescription: Defines which elements should be considered as part of your model.  \nType: [CSS selector](http://api.jquery.com/Types/#Selector)/[String](http://api.jquery.com/Types/#String)\n\nThis is the model related counterpart option of [jQuery's items option](http://api.jqueryui.com/sortable/#option-items).\n\n#### ui-preserve-size\n\n**ui-preserve-size** (default: undefined)  \nDescription: Set's the size of the sorting helper to the size of the original element before the sorting.  \nType: [Boolean](http://api.jquery.com/Types/#Boolean)/`undefined`\n\nThis is useful for elements that their size is dependent to other page characteristics.\nA representative example of such cases are `\u003ctable\u003e` `\u003ctr\u003e`s and `\u003ctd\u003e`s.\n\n### Attributes For Event Handling\n\nTo handle events with html bindings just define any expression to listed event attributes. \nIf you defined an attribute for this events and defined callback function in sortableOptions at the same time, the attribute based callback will be called first.\n\n*   **ui-sortable-start**\n*   **ui-sortable-activate**\n*   **ui-sortable-before-stop**\n*   **ui-sortable-update**\n*   **ui-sortable-remove**\n*   **ui-sortable-receive**\n*   **ui-sortable-deactivate**\n*   **ui-sortable-stop**\n\n\n\nExpression works on update event.\n```html\n\u003cul ui-sortable ng-model=\"items\" ui-sortable-update=\"expression\" \u003e\n  \u003cli ng-repeat=\"item in items\"\u003e{{ item }}\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n\nOn update event callBackFunction1 if called before callBackFunction2.\n```js\n$scope.sortableOptions = {\n  'update': callBackFunction2\n};\n```\n```html\n\u003cul ui-sortable=\"sortableOptions\" ng-model=\"items\" ui-sortable-update=\"callBackFunction1\" \u003e\n  \u003cli ng-repeat=\"item in items\"\u003e{{ item }}\u003c/li\u003e\n\u003c/ul\u003e\n```\n\n### Canceling\n\nInside the `update` callback, you can check the item that is dragged and cancel the sorting.\n\n```js\n$scope.sortableOptions = {\n  update: function(e, ui) {\n    if (ui.item.sortable.model == \"can't be moved\") {\n      ui.item.sortable.cancel();\n    }\n  }\n};\n```\n\n**Notes:**\n* `update` is the appropriate place to cancel a sorting, since it occurs before any model/scope changes but after the DOM position has been updated.\nSo `ui.item.scope` and the directive's `ng-model`, are equal to the scope before the drag start.\n* To [cancel a sorting between connected lists](https://github.com/angular-ui/ui-sortable/issues/107#issuecomment-33633638), `cancel` should be called inside the `update` callback of the originating list. A simple way to is to use the `ui.item.sortable.received` property:\n```js\nupdate: function(event, ui) {\n  if (// ensure we are in the first update() callback\n      !ui.item.sortable.received \u0026\u0026\n      // check that its an actual moving between the two lists\n      ui.item.sortable.source[0] !== ui.item.sortable.droptarget[0] \u0026\u0026\n      // check the size limitation\n      ui.item.sortable.model == \"can't be moved between lists\") {\n    ui.item.sortable.cancel();\n  }\n}\n```\n\n### jQueryUI Sortable Event order\n\n**Single sortable** [demo](http://codepen.io/thgreasi/pen/QKmWGj)\n```\ncreate\n\n/* dragging starts */\nhelper\nstart\nactivate\n\n/* multiple: sort/change/over/out */\n\nbeforeStop\nupdate    \u003c= call cancel() here if needed\ndeactivate\nstop\n```\n\n**Connected sortables** [demo](http://codepen.io/thgreasi/pen/YGazpJ)\n\n```\nlist A: create\nlist B: create\n\n/* dragging starts from sortable A to B */\nlist A: helper\nlist A: start\nlist B: activate\nlist A: activate\n\n/* both lists multiple: sort/change/over/out */\nlist A: sort\nlist A: change\nlist B: change\nlist B: over\nlist A: sort\nlist B: out\nlist A: sort\n\nlist A: beforeStop\nlist A: update    \u003c= call cancel() here if needed\nlist A: remove\nlist B: receive\nlist B: update\nlist B: deactivate\nlist A: deactivate\nlist A: stop\n```\n\nFor more details about the events check the [jQueryUI API documentation](http://api.jqueryui.com/sortable/).\n\n## Integrating with directives doing transclusion\nWrap the transclusion directive element with the ui-sortable directive and set the `items` to target your `ng-repeat`ed elements. Following best practices, it is also highly recommended that you add a `track by` expression to your `ng-repeat`. [Angular Material example](http://codepen.io/thgreasi/pen/NbyLVK).\n\n```js\nmyAppModule.controller('MyController', function($scope) {\n  $scope.items = [\"One\", \"Two\", \"Three\"];\n\n  $scope.sortableOptions = {\n    items: '.sortable-item'\n    // It is suggested to use the most specific cssselector you can,\n    // after analyzing the DOM elements generated by the transclusion directive\n    // eg: items: '\u003e .transclusionLvl1 \u003e .transclusionLvl2 \u003e .sortable-item'\n  };\n});\n```\n\n```html\n\u003cdiv ui-sortable=\"sortableOptions\" ng-model=\"items\"\u003e\n  \u003ca-transclusion-directive\u003e\n    \u003cdiv ng-repeat=\"item in items\" class=\"sortable-item\"\u003e{{ item }}\u003c/div\u003e\n  \u003c/a-transclusion-directive\u003e\n\u003c/div\u003e\n```\n\n## Examples\n\n- [Simple Demo](http://codepen.io/thgreasi/pen/wzmvgw)\n  - [Simple Attribute Handlers Demo](http://codepen.io/thgreasi/pen/JWbmjb)\n  - [Simple RequireJS Demo](http://codepen.io/thgreasi/pen/rrdNjj)\n  - [Simple Touch-Enabled Demo](http://codepen.io/thgreasi/pen/wzmvJv) using [jQuery UI Touch Punch](https://github.com/furf/jquery-ui-touch-punch/)\n  - [Multiple items sorting (ctrl+click)](http://codepen.io/thgreasi/pen/mJAcL) using [ui-sortable-multiselection](https://github.com/thgreasi/ui-sortable-multiselection)\n- [Connected Lists](http://codepen.io/thgreasi/pen/ozqNkr)\n- [Filtering](http://codepen.io/thgreasi/pen/XjEWRa) ([details](https://github.com/angular-ui/ui-sortable/issues/113))\n- [Ordering 1](http://codepen.io/thgreasi/pen/PGRomA) \u0026 [Ordering 2](http://plnkr.co/edit/gYsZZdFLeoeb5N9iemAO?p=preview) ([details](https://github.com/angular-ui/ui-sortable/issues/70))\n- [Cloning](http://codepen.io/thgreasi/pen/jrzOLA) ([details](https://github.com/angular-ui/ui-sortable/issues/139))\n- [Horizontal List](http://codepen.io/thgreasi/pen/zKWYdP)\n- [Tree with dynamic template](http://codepen.io/thgreasi/pen/VKXwzV)\n- Canceling\n  - [Connected Lists With Max Size](http://codepen.io/thgreasi/pen/zKWYEP)\n  - [Connected Lists Without Duplicates](http://codepen.io/thgreasi/pen/PGRoJr)\n  - [Promised Reverting](http://codepen.io/thgreasi/pen/ORvJzJ)\n- [Locked Items](http://codepen.io/thgreasi/pen/ALyBVQ)\n- [Draggable Handle](http://codepen.io/thgreasi/pen/PGRoRY)\n- [Drop Zone](http://codepen.io/thgreasi/pen/zKWYWR)\n- [Draggable-Sortable like interaction](http://codepen.io/thgreasi/pen/mAxdxk)\n- [Static HTML Sorting](http://codepen.io/thgreasi/pen/XjEWqV)\n\n## Integrations\n- [firebase](http://codepen.io/thgreasi/pen/repEZg?editors=0010)\n- [ui.bootstrap.accordion](http://plnkr.co/edit/TGIeeEbbvJwpJ3WRqo2z?p=preview)\n- [Angular Material](http://codepen.io/thgreasi/pen/NbyLVK) (thanks yenoh2)\n- [Asynchronous loading jQuery+jQueryUI with crisbeto/angular-ui-sortable-loader](https://github.com/crisbeto/angular-ui-sortable-loader)\n\n## Reporting Issues\n\nThe [above](#examples) pen's are provided as a good starting point to demonstrate issues, proposals and use cases.\nFeel free to edit any of them for your needs (don't forget to also update the libraries used to your version).\n\n## Testing\n\nWe use Karma and JSHint to ensure the quality of the code.  The easiest way to run these checks is to use grunt:\n\n```sh\nnpm install -g grunt-cli\nnpm install \u0026\u0026 bower install\ngrunt\n```\n\nThe karma task will try to open Firefox and Chrome as browser in which to run the tests.  Make sure this is available or change the configuration in `test\\karma.conf.js`.\n\n\n### Grunt Serve\n\nWe have one task to serve them all!\n\n```sh\ngrunt serve\n```\n\nIt's equal to run separately:\n\n* `grunt connect:server` : giving you a development server at [http://127.0.0.1:8000/](http://127.0.0.1:8000/).\n\n* `grunt karma:server` : giving you a Karma server to run tests (at [http://localhost:9876/](http://localhost:9876/) by default). You can force a test on this server with `grunt karma:unit:run`.\n\n* `grunt watch` : will automatically test your code and build your demo.  You can demo generation with `grunt build:gh-pages`.\n","funding_links":[],"categories":["JavaScript","Directive"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangular-ui%2Fui-sortable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fangular-ui%2Fui-sortable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangular-ui%2Fui-sortable/lists"}