How to use Nested Sort

The initial idea of Nested Sort came from the idea of having a JS class to receive a collection (array) of database records sorted on a specific order (the value of a specific column is the id of another column) and provide a way for changing the order of them via the HTML drag and drop (dnd) functionality.

So let's assume we have an array of "items":

[
  { id: 1, text: "Item 1" },
  { id: 11, text: "Item 1-1", parent: 1 },
  { id: 2, text: "Item 2" },
  { id: 3, text: "Item 3" },
  { id: 111, text: "Item 1-1-1", parent: 11 },
  { id: 112, text: "Item 1-1-2", parent: 11 },
  { id: 31, text: "Item 3-1", parent: 3 }
]

First put the following HTML element on your document where you want the list to be shown:

<div id="nested-sort-wrap"></div>

Now the following JS code would convert the array of items into a nested list and place it inside the HTML element you created earlier.

new NestedSort({
  data: [
    { id: 1, text: "Item 1" },
    { id: 11, text: "Item 1-1", parent: 1 },
    { id: 2, text: "Item 2" },
    { id: 3, text: "Item 3" },
    { id: 111, text: "Item 1-1-1", parent: 11 },
    { id: 112, text: "Item 1-1-2", parent: 11 },
    { id: 31, text: "Item 3-1", parent: 3 }
  ],
  actions: {
    onDrop(data) { // receives the new list structure JSON after dropping an item
      console.log(data)
    }
  },
  el: '#nested-sort-wrap', // a wrapper for the dynamically generated list element
  listClassNames: ['nested-sort'], // an array of custom class names for the dynamically generated list element
  renderListItem: (el, { id }) => {
    if (id === 2) el.textContent += ' (this is a custom rendered item)'
    return el
  }
})

Data mapping

The following table shows a map of different properties on every data item:

Data item properties
Name Role Required
id This is the unique identifier of the item Yes
text This appears as the list item text Yes
parent This is the id of the parent item No

But what if your items have different property names? As an example, let's say your data is structured as:

[
  { _id: 1, title: "Item 1" },
  { _id: 11, title: "Item 1-1", parent_id: 1 },
  { _id: 2, title: "Item 2" },
  { _id: 3, title: "Item 3" },
  { _id: 111, title: "Item 1-1-1", parent_id: 11 },
  { _id: 112, title: "Item 1-1-2", parent_id: 11 },
  { _id: 31, title: "Item 3-1", parent_id: 3 }
]

In this case, you can let Nested Sort know about this specific structure by using the propertyMap property of the object you're passing to the constructor (called Config object from now on):

new NestedSort({
  data: [
    { _id: 1, title: 'Item 1' },
    { _id: 11, title: 'Item 1-1', parent_id: 1 },
    { _id: 2, title: 'Item 2' },
    { _id: 3, title: 'Item 3' },
    { _id: 111, title: 'Item 1-1-1', parent_id: 11 },
    { _id: 112, title: 'Item 1-1-2', parent_id: 11 },
    { _id: 31, title: 'Item 3-1', parent_id: 3 }
  ],
  propertyMap: {
    id: '_id',
    parent: 'parent_id',
    text: 'title',
  },
  el: '#nested-sort-wrap',
  listClassNames: ['nested-sort']
})

Custom render of list items (v5.1.0)

The default list item element rendered by the library might not be ideal for every use case. Therefore, a hook has been introduced to give us more control over the list items html content. The renderListItem option is supposed to be a function which receives the following 2 arguments and returns a list item element:

  1. el: the default list item element created by the library
  2. item: the representative data item
new NestedSort({
  data: [
    { id: 1, text: "Item 1" },
  ],
  renderListItem: (el, { id }) => {
    if (id === 1) el.textContent += ' (this is a custom rendered item)'
    return el
  },
  ...otherOptions
})