13

I have a list of Students that I should display to user on a web page in tabular format.
The items are stored in DB along with SortOrder information.

On the web page, user can rearrange the list order by dragging and dropping the items to their desired sort order, similar to this post.

Below is a screenshot of my test page.
enter image description here

In the above example, each row has sort order info attached to it. When I drop John Doe (Student Id 10) above the Student Id 1 row, the list order should now be: 2, 10, 1, 8, 11.

What's the optimistic (less resource hungry) way to store and update Sort Order information?

My only idea for now is, for every change in the list's sort order, every object's SortOrder value should be updated, which in my opinion is very resource hungry.

Just FYI: I might have at most 25 rows in my table.

2
  • 1
    Do you need to have this sort order persisted on the server side, or is having it just on the client side sufficient?
    – deterb
    Jun 23, 2012 at 2:22
  • 1
    I should store the order on server-side. It doesnt matter if the order is stored on every drag-drop or by clicking a button once and for all.
    – Alexander
    Jun 24, 2012 at 21:32

4 Answers 4

12

I have think of something, which can reduce your queries. Here in my example, I have added a new column for sorting named pos. So, initially without any dragging your table will be like -

Initial State

Now, Lets consider that you dragged the Item 4 between Item 1 & Item 2. Now, new pos value for Item 4 will be (20 + 10) / 2, which is 15. So, You will only need to update a single row in database. And, you will get -

After Drag

Here is a flowchart with the edge cases. i is the new array index of your row after dragged -

Flow Chart

This flowchart doesn't handle ArrayOutOfBound checks. And, for edge cases you will need more than one query.

Since you have only 25 rows, you can take a very big value (e.g. 10,000) for the pos difference (I took 10 for this example). The bigger the value is, the less it will collide.

7
  • This is a nice approach. Notice that you'll have to recalculate the whole (or a big part of) the ordering info if there's no room lest to insert an item. It would be a rare enough event to put up with.
    – 9000
    Jan 11, 2016 at 18:14
  • @9000 you can use decimal instead of integer to avoid the problem.
    – Rifat
    Jan 12, 2016 at 9:45
  • if you have Item A with position 123 and Item C with position 124, there's no easy way to put Item B between them. One solution would be using fractional numbers (e.g. floats), but they have a limited precision, too. Sometimes you're better off doing a renumbering, normalizing intervals, and keeping things simple.
    – 9000
    Jan 12, 2016 at 15:22
  • So when you do i--, you're just subtracting by 1. Isn't there a different interval you could subtract by to prevent eventual collisions?
    – muttley91
    Jul 26, 2016 at 20:25
  • @Rifat even decimals have a limited precision, so they will collide too.
    – SCI
    Dec 29, 2017 at 12:58
3

Personally I would return a JSON array for the data from the back end. Then I would use JavaScript (JQuery or knockout) to display and sort and re-sort the data. That way the sorting has zero load on the server.

0

You are looking for a resource-friendly way to handling this but user-friendly perspective is also a must. I recommend individual requests after each reordered item. Each call allows for you to check if accepted or failed.

  • Failed responses will reset the view and displays an message to the end-user.
  • Accepted requests simple allows continued editing.

Alternatively, using a JSON object (@tom-squires) is a good idea to reduce HTTP overhead and server-side processing but ultimately requires more code to handle requests on the server and client side. If that is OK, passing the object to the server is most technically efficient. It also allows for a delay of a couple seconds to allow for multiple reorders before a single request, if you desire this.

Keep in mind, in order to provide a user with a feedback from failed requests you would have to parse a response JSON object from the server to figure out which item failed and reset the UI based on that.

-1

Something like this in the drop event handler, where e is the DnD event.

        ....
        if (e.Action == DragAction.Drop)
        {
            foreach(var item in Items)
            {
                if (e.NewIndex == e.OldIndex) // Dropped in same place
                    return;
                if(e.OldIndex > e.NewIndex) // Moved Up
                {
                    if (item.SortOrder >= e.NewIndex && item.SortOrder < e.OldIndex)
                    {
                        item.SortOrder ++;
                    }
                }
                else // Moved Down
                {
                    if (item.SortOrder> e.OldIndex && item.SortOrder < e.NewIndex) 
                    {
                        item.SortOrder --;
                    }
                }   
            }
            ((Student)e.ItemData).SortOrder = e.NewIndex;
        }
    ...

Not the answer you're looking for? Browse other questions tagged or ask your own question.