A Valuable Hint: Consistent Sorting Between Vue and Laravel

Dr. Adam Nielsen
4 min readOct 17, 2024

--

Sorting does not work?

Working with Laravel collections can be incredibly powerful, but a small oversight can lead to unexpected behavior when converting collections to JSON. If you’ve ever encountered a situation where your sorted data ends up in a mixed order on the frontend, the solution might lie in a simple method: values().

Example: A Sorted Collection Gone Wrong

Let’s look at a concrete example. Suppose you have a collection of items with label values, and you want to sort them alphabetically by the label:

$expertiseOptions = collect([
['id' => 5, 'label' => 'Banana'],
['id' => 2, 'label' => 'Apple'],
['id' => 11, 'label' => 'Grape'],
['id' => 1, 'label' => 'Cherry'],
['id' => 21, 'label' => 'Mango'],
]);

// Sort by 'label'
$sortedOptions = $expertiseOptions->sortBy('label');

After sorting, you might expect the collection to look like this:

// Expected order
[
['id' => 2, 'label' => 'Apple'],
['id' => 5, 'label' => 'Banana'],
['id' => 1, 'label' => 'Cherry'],
['id' => 11, 'label' => 'Grape'],
['id' => 21, 'label' => 'Mango'],
]

However, if you don’t call values(), the keys are not reindexed. Instead, the collection retains its original keys:

// Actual order without values()
[
1 => ['id' => 2, 'label' => 'Apple'],
0 => ['id' => 5, 'label' => 'Banana'],
3 => ['id' => 1, 'label' => 'Cherry'],
2 => ['id' => 11, 'label' => 'Grape'],
4 => ['id' => 21, 'label' => 'Mango'],
]

In PHP, arrays can have non-sequential keys, such as 1, 2, 4, 5, rather than strictly 0, 1, 2, 3, .... In many programming languages, this concept is referred to as a hashmap rather than an array. For example, in JavaScript, a collection is only considered an array if its keys are consecutive integers starting from 0. Otherwise, it is treated as an object. This difference in interpretation is what causes the sorting issue. Let’s dive into the next section for a more detailed explanation.

JSON Representation Without values()

This collection is converted to a JSON object (which happens behind the scenes if you use Inertia.js), because the index values are not in sequence. It might look like this:

{
"1": { "id": 2, "label": "Apple" },
"0": { "id": 5, "label": "Banana" },
"3": { "id": 1, "label": "Cherry" },
"2": { "id": 11, "label": "Grape" },
"4": { "id": 21, "label": "Mango" }
}

Since the JSON data is treated as an object with non-sequential keys, Vue will iterate over these keys in an unexpected order:

<div v-for="expertise in expertiseOptions" :key="expertise.id">
<p>{{ expertise.label }}</p>
</div>

Given the above JSON, Vue will render the items in the following order:

Banana
Apple
Grape
Cherry
Mango

This happens because JavaScript sorts object keys (which are treated as strings) in a specific order when iterating over them. It treats "1", "0", "3", etc., as strings, leading to a lexicographic sort that may differ from the intended numeric order. If you had number higher then 10, the sorting would be 1,11,12,13,14,2,21,23..

The Solution: Using values()

To fix this, you simply need to call values() on your collection before converting it to JSON:

$sortedOptions = $sortedOptions->values();

By using values(), Laravel reindexes the collection to have sequential keys (0, 1, 2,...).

// Order with values()
[
0 => ['id' => 2, 'label' => 'Apple'],
1 => ['id' => 5, 'label' => 'Banana'],
2 => ['id' => 1, 'label' => 'Cherry'],
3 => ['id' => 11, 'label' => 'Grape'],
4 => ['id' => 21, 'label' => 'Mango'],
]

Now, the JSON output will be an array, and no longer an object:

[
{ "id": 2, "label": "Apple" },
{ "id": 5, "label": "Banana" },
{ "id": 1, "label": "Cherry" },
{ "id": 11, "label": "Grape" },
{ "id": 21, "label": "Mango" }
]

In this case, the JSON is treated as an array by JavaScript, which guarantees the order of elements. When Vue iterates over this data, it will preserve the order as intended:

Apple
Banana
Cherry
Grape
Mango

Conclusion

The values() method might seem trivial, but it plays a crucial role in ensuring that your sorted data maintains its order on the frontend. This small adjustment can save you from the headache of debugging unexpected JSON behavior and ensures a smooth data flow between your Laravel backend and JavaScript frontend.

Remember, the next time you sort a collection and pass it to your frontend, don’t forget to ->values(). It might be the key to keeping your data in the right order!

--

--

Dr. Adam Nielsen
Dr. Adam Nielsen

Written by Dr. Adam Nielsen

PHD in math. and Laravel / Vue Full-Stack-Developer

No responses yet