{"id":13481058,"url":"https://github.com/SortableJS/ngx-sortablejs","last_synced_at":"2025-03-27T11:31:36.106Z","repository":{"id":39017485,"uuid":"62609044","full_name":"SortableJS/ngx-sortablejs","owner":"SortableJS","description":"Angular 2+ binding to SortableJS. Previously known as angular-sortablejs","archived":false,"fork":false,"pushed_at":"2024-03-14T01:09:47.000Z","size":1915,"stargazers_count":466,"open_issues_count":100,"forks_count":160,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-10-27T05:44:35.925Z","etag":null,"topics":["angular","angular-sortablejs","detect-changes","drag","draggable","drop","ngx-sortablejs","sortable","sortablejs"],"latest_commit_sha":null,"homepage":"https://sortablejs.github.io/ngx-sortablejs/","language":"TypeScript","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/SortableJS.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-07-05T05:43:31.000Z","updated_at":"2024-10-04T18:33:09.000Z","dependencies_parsed_at":"2024-01-12T18:39:29.417Z","dependency_job_id":"adadadd0-6822-4672-8f84-0a295497e2bc","html_url":"https://github.com/SortableJS/ngx-sortablejs","commit_stats":{"total_commits":194,"total_committers":25,"mean_commits":7.76,"dds":0.5051546391752577,"last_synced_commit":"a9dbb81efbab7d740f177635738990e0c7a4d34e"},"previous_names":["sortablejs/angular-sortablejs"],"tags_count":53,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SortableJS%2Fngx-sortablejs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SortableJS%2Fngx-sortablejs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SortableJS%2Fngx-sortablejs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SortableJS%2Fngx-sortablejs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SortableJS","download_url":"https://codeload.github.com/SortableJS/ngx-sortablejs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222239502,"owners_count":16953961,"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":["angular","angular-sortablejs","detect-changes","drag","draggable","drop","ngx-sortablejs","sortable","sortablejs"],"created_at":"2024-07-31T17:00:48.208Z","updated_at":"2024-10-30T14:31:14.861Z","avatar_url":"https://github.com/SortableJS.png","language":"TypeScript","readme":"# ngx-sortablejs\n\nThis package is an Angular 2+ binding for [Sortable.js](https://github.com/RubaXa/Sortable). Supports standard arrays and Angular `FormArray`.\n\nPreviously known as angular-sortablejs.\n\n## Demo\n\nSee the library in action in a [demo](https://sortablejs.github.io/ngx-sortablejs) project (the source is located in `src` directory).\n\nTrees are also supported: [tree with fake root element (\\*ngFor once, root can also be hidden anyway)](https://stackblitz.com/edit/angular-o1pq84) or [without (\\*ngFor 2 times)](https://stackblitz.com/edit/angular-ptu94s).\n\n## Installation\n\n```sh\nnpm i -S ngx-sortablejs sortablejs\nnpm i -D @types/sortablejs\n```\n\nYou 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.\n\n## Usage\n\nFirst, import `SortablejsModule.forRoot({ /* and here some global settings if needed */ })` into the root module of your application:\n\n```typescript\nimports: [\n  // ...\n  SortablejsModule.forRoot({ animation: 150 }),\n  // ...\n]\n```\n\nThen import `SortablejsModule` into the other angular modules where you want to use it:\n\n```typescript\nimports: [\n  // ...\n  SortablejsModule,\n  // ...\n]\n```\n\nThen 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.\n\n## Directive API\n\n- `sortablejs` - directive, accepts model to be auto-updated (see examples below)\n- `sortablejsContainer` - directive input, CSS selector for the sortable container, string. Mostly required for frameworks that wrap the content into the elements where it is impossible to access the real container element (e.g. @angular/material). Example: `sortablejsContainer=\".mat-grid-list\"`\n- `sortablejsOptions` - directive input, sortable options to pass in. Please note that in order to change the options later the whole object needs to be recreated, see below\n- `sortablejsInit` - directive output, returns the current Sortable instance. Example: `(sortablejsInit)=\"sortableInstance = $event\"`\n\n## Simple sortable list\n\n```typescript\nimport { Component } from '@angular/core';\n\n@Component({\n    selector: 'my-app',\n    template: `\n      \u003ch2\u003eDrag / drop the item\u003c/h2\u003e\n      \u003cdiv [sortablejs]=\"items\"\u003e\n        \u003cdiv *ngFor=\"let item of items\"\u003e{{ item }}\u003c/div\u003e\n      \u003c/div\u003e\n    `\n})\nexport class AppComponent {\n   items = [1, 2, 3, 4, 5];\n}\n```\n\n### Passing the options\n\nPass the options with `sortablejsOptions` property.\n\n```typescript\nimport { Component } from '@angular/core';\n\n@Component({\n    selector: 'my-app',\n    template: `\n      \u003ch2\u003eDrag / drop the item\u003c/h2\u003e\n      \u003cdiv [sortablejs]=\"items\" [sortablejsOptions]=\"{ animation: 150 }\"\u003e\n        \u003cdiv *ngFor=\"let item of items\"\u003e{{ item }}\u003c/div\u003e\n      \u003c/div\u003e\n    `\n})\nexport class AppComponent {\n   items = [1, 2, 3, 4, 5];\n}\n```\n\n### Tracking lists update events\n\nYou can use the options' `onUpdate` method to track the changes (see also *Passing the options* section):\n\n```ts\nconstructor() {\n  this.options = {\n    onUpdate: (event: any) =\u003e {\n      this.postChangesToServer();\n    }\n  };\n}\n```\n\nIf you use FormArray you are able to choose a more elegant solution:\n\n```ts\npublic items = new FormArray([\n  new FormControl(1),\n  new FormControl(2),\n  new FormControl(3),\n]);\n\nconstructor() {\n  this.items.valueChanges.subscribe(() =\u003e {\n    this.postChangesToServer(this.items.value);\n  });\n}\n```\n\nbut note, that here you will be able to take the whole changed array only (no oldIndex / newIndex).\n\n### Updating the options\n\nYou 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](https://github.com/RubaXa/Sortable) to set the new option values.\n\u003e Note: It will only detect changes when a brand new options object is passed, not deep changes.\n\n### Drag \u0026 drop between two lists\n\nThe only thing which should be done is assigning the `group` option to the both list. Everything else is handled automatically.\n\n```typescript\nimport { Component } from '@angular/core';\nimport { SortablejsOptions } from 'ngx-sortablejs';\n\n@Component({\n    selector: 'my-app',\n    template: `\n    \u003ch2\u003eDrag / drop the item\u003c/h2\u003e\n    \u003ch3\u003elist 1\u003c/h3\u003e\n    \u003cdiv class=\"items1\" [sortablejs]=\"items1\" [sortablejsOptions]=\"options\"\u003e\n      \u003cdiv *ngFor=\"let item of items1\"\u003e{{ item }}\u003c/div\u003e\n    \u003c/div\u003e\n    \u003ch3\u003elist 2\u003c/h3\u003e\n    \u003cdiv class=\"items2\" [sortablejs]=\"items2\" [sortablejsOptions]=\"options\"\u003e\n      \u003cdiv *ngFor=\"let item of items2\"\u003e{{ item }}\u003c/div\u003e\n    \u003c/div\u003e\n    `\n})\nexport class AppComponent {\n   items1 = [1, 2, 3, 4, 5];\n   items2 = ['a', 'b', 'c', 'd', 'e'];\n\n   options: SortablejsOptions = {\n     group: 'test'\n   };\n}\n```\n\n### Drag \u0026 drop between two lists: clone mode\n\nThe 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 `ngx-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.\n\nIf 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.\n\n```typescript\nimport { Component } from '@angular/core';\nimport { SortablejsOptions } from 'ngx-sortablejs';\n\n@Component({\n    selector: 'my-app',\n    template: `\n    \u003ch2\u003eDrag / drop the item\u003c/h2\u003e\n    \u003ch3\u003elist 1\u003c/h3\u003e\n    \u003cdiv class=\"items1\" [sortablejs]=\"items1\" [sortablejsOptions]=\"options\" [sortablejsCloneFunction]=\"myCloneImplementation\"\u003e\n      \u003cdiv *ngFor=\"let item of items1\"\u003e{{ item }}\u003c/div\u003e\n    \u003c/div\u003e\n    \u003ch3\u003elist 2\u003c/h3\u003e\n    \u003cdiv class=\"items2\" [sortablejs]=\"items2\" [sortablejsOptions]=\"options\" [sortablejsCloneFunction]=\"myCloneImplementation\"\u003e\n      \u003cdiv *ngFor=\"let item of items2\"\u003e{{ item }}\u003c/div\u003e\n    \u003c/div\u003e\n    `\n})\nexport class AppComponent {\n\n  myCloneImplementation = (item) =\u003e {\n    return item; // this is what happens if sortablejsCloneFunction is not provided. Add your stuff here\n  }\n\n}\n```\n\n### Bind events inside Angular zone\n\nBy default, the boolean parameter **runInsideAngular** is set to **false**.\nThis 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.\n\nIf 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).\n\n### Configure the options globally\n\nIf 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:\n\n```typescript\nimports: [\n  // ...\n  // any properties and events available on original library work here as well\n  SortablejsModule.forRoot({\n    animation: 150\n  }),\n  // ...\n]\n```\n\nThis value will be used as a default one, but it can be overwritten by a local `sortablejsOptions` property.\n\n## Angular Material specifics\n\n### Expansion panel\n\nThere is a bug with expansion panel which appears because angular material does not really hide the content of panel, but uses `visibility: hidden`. What we need to do is to actually totally hide it from the DOM instead.\n\nJust add this to your **global** styles\n\n```css\nmat-expansion-panel.sortable-drag .mat-expansion-panel-content {\n  display: none;\n}\n```\n\nand the issue should be resolved.\n\n### Ripple effect\n\nThe elements with ripple effect like `mat-list-item` are affected. The dragging is broken because there is a [div created right under the cursor](https://github.com/angular/material2/blob/master/src/lib/core/ripple/ripple-renderer.ts#L142) and the webkit has no idea what to do with it.\n\nThere are two solutions:\n\n1. Disable the ripple effect\n\n```ts\n\u003ca mat-list-item [disableRipple]=\"true\"\u003e\n```\n\n2. Use `handle` property and block propagation of `mousedown` and `touchstart` events on the handler to prevent ripple.\n\n```ts\n\u003cdiv [sortablejs]=\"...\" [sortablejsOptions]=\"{ handle: '.handle' }\"\u003e\n  \u003ca mat-list-item *ngFor=\"let a of b\" [routerLink]=\"...\" routerLinkActive=\"active\"\u003e\n    \u003cmat-icon matListIcon\n              class=\"handle\"\n              (mousedown)=\"$event.stopPropagation()\"\n              (touchstart)=\"$event.stopPropagation()\"\u003edrag_handle\u003c/mat-icon\u003e {{ a }}\n  \u003c/a\u003e\n\u003c/div\u003e\n```\n\n## How it works\n\nThe model is automatically updated because you pass the `items` as `\u003cdiv [sortablejs]=\"items\"\u003e`. The `items` variable can be either an ordinary JavaScript array or a reactive forms `FormArray`.\n\nIf you won't pass anything, e.g. `\u003cdiv sortablejs\u003e`, the items won't be automatically updated, thus you should take care of updating the array on your own using standard `Sortable.js` events.\n\nOriginal 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. `\u003cdiv sortablejs\u003e` the data binding is skipped and only your event handlers will be fired.\n\nImportant: 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`.\n\n## License\n\nMIT\n","funding_links":[],"categories":["Uncategorized"],"sub_categories":["Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSortableJS%2Fngx-sortablejs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSortableJS%2Fngx-sortablejs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSortableJS%2Fngx-sortablejs/lists"}