Skip to main content

Categories Reorder with Drag-Drop

Premium
6 min read

Comments & Discussion

FA
Farooq Ahmed ✓ Link copied!

hi dos the 'position' in categories table migration had to be nullable by default.it is showing error when i migrate:fresh and insert seed data

PK
Povilas Korop ✓ Link copied!

I think by default its value is 0, but can't guarantee: what is the actual error test and what seed data are you using?

B
basherdesigns ✓ Link copied!

I made the position default to 9999, so new Categories will be at the end. Or if you default to 0 it will be very first category

RB
Rajesh Budhathoki ✓ Link copied!

While you follow along and encountred some errors as I did, I suggest you to make some amendments. To seed position rows. Amend in CategoryFactory.php:

ublic function definition(): array
{
$country = fake()->unique()->country();
 
return [
'name' => $country,
'slug' => Str::slug($country),
'position' => fake()->numberBetween(1, 10),
];
}

Import namespace in CategoriesList.php

use Illuminate\Support\Collection;

For better UX and Web accessibility aspect, change buton cursor class to cursor-move in categories-list.blade.php:

<button wire:sortable.handle class="cursor-move">
// ...
</button>
E
Emruardo ✓ Link copied!

I've added the code to Category model. Position has same number as id on seeding or new creation of Category.

 
protected static function boot()
{
parent::boot();
 
static::created(function ($model) {
$model->position = $model->id;
$model->save();
});
}
RB
Rajesh Budhathoki ✓ Link copied!

Where and how can we dump $list array to see what's inside?

If we paginate 10 the $categories per page, how can we drag and drop 11 category to the first position?

N
Nerijus ✓ Link copied!

You can dump where we update the order. So it would be updateOrder method. To other page you cannot drag and drop.

E
Emruardo ✓ Link copied!

If an item will be positioned in another page than page 1, order number begins from 1. This causes that there are 2 categories with the same position number. The refactoring in CategoriesList helped me to achieve the problem.

 
class CategoriesList extends Component
{
// ...
public $currentPage = 1;
public $perPage = 10;
 
// ...
public function updateOrder($list)
{
foreach ($list as $item) {
$cat = $this->categories->firstWhere('id', $item['value']);
$order = $item['order'] + (($this->currentPage - 1) * $this->perPage);
if ($cat['position'] != $order) {
Category::where('id', $item['value'])->update(['position' => $order]);
}
}
}
// ...
public function render()
{
$cats = Category::orderBy('position')->paginate($this->perPage);
$links = $cats->links();
$this->currentPage = $cats->currentPage();
$this->categories = collect($cats->items());
// ...
}
B
basherdesigns ✓ Link copied!

Now how can you move a category that is on the second page to the first page? This seems to not be working.

PK
Povilas Korop ✓ Link copied!

Good question, I don't think it's possible with drag-drop. I guess it's better to build a separate button like "move one page up" or something.

R
RangerCoder99 ✓ Link copied!

Again so many issues following alone had to check the comments for fixes, and this comments were posted a month(s) ago not sure why the tutorial text was not updated. Not trying to be mean just giving honest feedback.

ED
Emre Dikmen ✓ Link copied!

CategoryFactory position will increase in order.

public function definition(): array
{
$name = $this->faker->sentence(5);
static $position = 1;
 
return [
'name' => $name,
'slug' => function (array $attributes) {
return Str::slug($attributes['name']);
},
'is_active' => $this->faker->boolean,
'position' => $position++
];
}
 
```
ED
Emre Dikmen ✓ Link copied!

Or you can increase the position value this way.

'position' => Category::max('position') + 1

A
augusto-dmh ✓ Link copied!

@Emre Dikem Yep, that's the approach i took too.

A
alin ✓ Link copied!
foreach ($list as $item) {
$cat = $this->categories->firstWhere('id', $item['value']);
 
if ($cat['position'] != $item['order']) {
Category::where('id', $item['value'])->update(['position' => $item['order']]);
}
}

Why did you not use the variable $cat inside the if? Why did you fetch Category::where...? I assume there are some advantages but i can't figure it out.

M
Modestas ✓ Link copied!

It is used inside the if, but you might be confusing this because it looks like a database query.

The $cat variable comes from a collection, not the databse in this case (it's missing the categories()) and that makes it work with the data that is already loaded as a relationship.

A
alin ✓ Link copied!

Thank you for your quick reply! Appreciate it, and the whole job you are doing here.

We'd Love Your Feedback

Tell us what you like or what we can improve

Feel free to share anything you like or dislike about this page or the platform in general.