DEV Community

Patrik Braborec
Patrik Braborec

Posted on • Edited on

JavaScript Object Items Order

The Bug πŸ›

I had to solve an issue with the order of items in a dropdown. The problem was that items in the dropdown were sorted wrongly (in a different way than from the server).

For example, data from the server were in this order:

const items = [{
    id: "/product/id/2",
    title: "product 2"
  },
  {
    id: "/product/id/1",
    title: "product 1"
  },
  {
    id: "/product/id/4",
    title: "product 4"
  },
  {
    id: "/product/id/5",
    title: "product 5"
  },
];
Enter fullscreen mode Exit fullscreen mode

There was a function which mapped that data from the server into an object, something like this:

function mapToObject(items) {
  return items.reduce((acc, item) => {
    acc[item.id] = item;
    return acc;
  }, {});
};
Enter fullscreen mode Exit fullscreen mode

Because JavaScript (for objects) does not (always) follow the insertion order, the result of that function was:

{
  "/product/id/1": {
    id: "/product/id/1",
    title: "product 1"
  },
  "/product/id/2": {
    id: "/product/id/2",
    title: "product 2"
  },
  "/product/id/4": {
    id: "/product/id/4",
    title: "product 4"
  },
  "/product/id/5": {
    id: "/product/id/5",
    title: "product 5"
  }
}
Enter fullscreen mode Exit fullscreen mode

The result of that function led to the wrong order of items in the dropdown.

Why does it happen? πŸ”

Property order in normal Objects is a complex subject in JavaScript.

While in ES5 explicitly no order has been specified, ES2015 defined an order in certain cases, and successive changes to the specification since have increasingly defined the order (even, as of ES2020, the for-in loop's order). Given is the…

The Solution πŸš€

I wanted to keep "similar structure" because the dropdown can have a lot of items (for example, I would have to iterate over all items to get a selected item) so I solved the issue with a Map object - guarantees the keys will be iterated in order of insertion and it has similar features like Object.

function toMappedItems(items) {
  const map = new Map();
  items.forEach(item => map.set(item.id, item));
  return map;
}
Enter fullscreen mode Exit fullscreen mode

The result of that new function is:

0: {"/product/id/2" => {id: "/product/id/2", ...}}
1: {"/product/id/1" => {id: "/product/id/1", ...}}
2: {"/product/id/4" => {id: "/product/id/4", ...}}
3: {"/product/id/5" => {id: "/product/id/5", ...}}
Enter fullscreen mode Exit fullscreen mode

So it is easy to work with that result and it keeps the order of items from the server.

The whole problem and solution are "simplified". The main take away is to not rely on the order in Object. πŸŽ‰

Top comments (0)