jQuery UI
Sortable
Database Integration
Web Development
JavaScript

jQuery UI Sortable, then write order into a database

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Making a list draggable is only half of the feature. Once the user drops items into a new order, the application needs to store that order so the next page load, mobile client, or teammate sees the same sequence.

Give Each Item A Stable Identifier

The browser should not send "item number three moved to position one" without telling the server which record that actually refers to. The safe pattern is to render each sortable item with a stable database identifier.

html
1<ul id="tasks">
2  <li data-id="101">Write docs</li>
3  <li data-id="102">Review PR</li>
4  <li data-id="103">Ship release</li>
5</ul>

Using a data-id attribute keeps the DOM clean and avoids hard-coding application logic into element ids.

Capture The New Order After Sorting

jQuery UI Sortable fires an update event when the user changes the order. At that moment, you can read the current item sequence and send it to the server.

javascript
1$(function () {
2  $("#tasks").sortable({
3    update: function () {
4      const orderedIds = $(this)
5        .children()
6        .map(function () {
7          return Number($(this).data("id"));
8        })
9        .get();
10
11      console.log(orderedIds);
12    }
13  });
14});

That array is the real payload. It tells the backend exactly which records now belong in which positions.

Send The Order To The Server

Once you have the ordered ids, post them to an endpoint responsible for persisting the ranking.

javascript
1$(function () {
2  $("#tasks").sortable({
3    update: async function () {
4      const orderedIds = $(this)
5        .children()
6        .map(function () {
7          return Number($(this).data("id"));
8        })
9        .get();
10
11      await fetch("/api/tasks/reorder", {
12        method: "POST",
13        headers: {
14          "Content-Type": "application/json"
15        },
16        body: JSON.stringify({ orderedIds })
17      });
18    }
19  });
20});

Only send stable ids. Do not trust raw visual indexes from the page as if they were database keys.

Persist The New Positions In One Transaction

On the server, store the new order in a numeric column such as sort_order or position. Wrapping the updates in a transaction prevents half-written ordering if something fails partway through.

javascript
1app.post("/api/tasks/reorder", async (req, res) => {
2  const { orderedIds } = req.body;
3
4  await db.transaction(async (trx) => {
5    for (let index = 0; index < orderedIds.length; index += 1) {
6      await trx("tasks")
7        .where({ id: orderedIds[index] })
8        .update({ sort_order: index + 1 });
9    }
10  });
11
12  res.json({ ok: true });
13});

The exact database library does not matter much. The important design choice is that the browser sends the ids in order, and the server translates that ordered array into stored numeric positions.

When you read the list back later, sort by the persisted column:

sql
select id, title, sort_order
from tasks
order by sort_order asc;

Without that final order by, the save appears to work while the page still renders in an arbitrary sequence.

Think About Concurrency And UX

Fast drag operations can produce multiple rapid update events. In a polished interface, you often want to debounce saves or disable further writes until the current request finishes.

Concurrent edits are another concern. If two users reorder the same list at nearly the same time, the last write usually wins unless you add version checks or list-level locking. That is not a jQuery UI problem; it is a persistence rule you need to define explicitly.

Common Pitfalls

  • Sending screen positions without stable record ids.
  • Saving the order but forgetting to sort by that saved column on the next read.
  • Updating rows outside a transaction and leaving the list half-persisted.
  • Firing overlapping save requests during rapid dragging.
  • Accepting submitted ids without checking that they belong to the current list or user.

Summary

  • Attach a stable id to every sortable item.
  • Read the new order from the DOM when the update event fires.
  • Send the ordered ids to the server and persist them in a numeric position column.
  • Use a transaction and reload the list with order by so the saved order actually appears consistently.

Course illustration
Course illustration

All Rights Reserved.