Skip to main content

Categories Reorder with Drag-Drop

Premium
6 min read
Farooq Ahmed avatar

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

Povilas Korop avatar

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?

basherdesigns avatar

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

Rajesh Budhathoki avatar

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>
👍 4
😍 1
Emruardo avatar

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();
});
}
👍 2
Rajesh Budhathoki avatar

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?

Nerijus avatar

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

Emruardo avatar

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());
// ...
}
👍 1
basherdesigns avatar

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

Povilas Korop avatar

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.

RangerCoder99 avatar

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.

👍 3
Emre Dikmen avatar

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++
];
}
 
```
Emre Dikmen avatar

Or you can increase the position value this way.

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

augusto-dmh avatar

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

alin avatar
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.

Modestas avatar

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.

alin avatar

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

Richard A. Hoyle avatar

the position Is Not working at all I am not getting any arrers but at the same time it will not work eather

Not shour where you have the following code I just can not find it in the GutHub repository any help would be apreciated!

protected static function boot() { parent::boot();

static::created(function ($model) {
$model->position = $model->id;
$model->save();
});

}

Nerijus avatar

Repository is in the last lesson: https://github.com/LaravelDaily/Laravel-Livewire-Orders Don't forget that this course uses Livewire v3, but you mentioned you use v4.