This Laravel Nova package allows you to reorder models in a Nova resource's index view using drag & drop.
Uses Spatie's eloquent-sortable under the hood.
- Laravel Nova >= 2.10.0
- For Laravel Nova < 2.10.0 use
nova-sortable
version1.1.3
- Drag & drop reorder within one page of resources
- Move to start and end arrows (makes item first/last)
- Localization
- Everything from eloquent-sortable
Install the package in a Laravel Nova project via Composer:
# Install package
composer require optimistdigital/nova-sortable
Add an order field to the model using Laravel migrations:
# Add order field with default value
Schema::table('some_model', function (Blueprint $table) {
$table->integer('sort_order');
});
DB::statement('UPDATE some_model SET sort_order = id');
Implement the Spatie's eloquent-sortable
interface and apply the trait:
use Spatie\EloquentSortable\Sortable;
use Spatie\EloquentSortable\SortableTrait;
class MyModel extends Eloquent implements Sortable
{
use SortableTrait;
public $sortable = [
'order_column_name' => 'sort_order',
'sort_when_creating' => true,
];
...
}
Apply HasSortableRows
trait from this package on the Resource:
use OptimistDigital\NovaSortable\Traits\HasSortableRows;
class MyResource extends Resource
{
use HasSortableRows;
...
}
The translation file(s) can be published by using the following publish command:
php artisan vendor:publish --provider="OptimistDigital\NovaSortable\ToolServiceProvider" --tag="translations"
You can add your translations to resources/lang/vendor/nova-sortable/
by creating a new translations file with the locale name (ie et.json
) and copying the JSON from the existing en.json
.
NB! Sorting is impossible when your pivot table has multiple items with the same ID pairs.
First, add a new column for the sort order data to the pivot table. Default name is sort_order
, but it's configurable if you create a new Pivot
class and add the $sortable
property to it.
Next, set sort_on_pivot
to true
on the main model's (not the pivot class') $sortable = []
array.
public $sortable = [
'order_column_name' => 'sort_order',
'sort_when_creating' => true,
'sort_on_pivot' => true,
];
Finally, add sorting to the pivot query manually. On the parent model (on which the pivots are displayed), add orderBy()
to the pivot query definition like so:
public function products()
{
return $this->belongsToMany(Product::class, 'order_product')
->withPivot(OrderProduct::getPivotFields())
->using(OrderProduct::class)
->orderBy('order_product.sort_order'); // The `order_product` pivot table name prefix is required!
}
Let's imagine we have User
and UserGroup
resources, where UserGroup
is sorted by nova-sortable.
You may want to have your users listed in the same order as the order of groups they belong to. So,
users from the first group, then users from the second group, etc. You can change the default ordering for
a Nova resource by adding applyOrderings
function to your resource class like so:
protected static function applyOrderings($query, array $orderings)
{
if (empty($orderings)) {
$query->join('user_groups', 'users.user_group_id', '=', 'user_groups.id');
$query->select('users.*');
$orderings = [
'user_groups.priority' => 'asc',
// 'users.name' => 'asc', // to make users in each user group get sorted by their name
// 'users.email' => 'asc', // to make users in the same group and with the same name get
// sorted by their email
// etc.
];
}
return parent::applyOrderings($query, $orderings);
}
This will apply ordering to the index page and index fragments (e.g. HasMany
). Please note that
BelongsTo
field always sorts all items alphabetically (due to sortBy('display')
in
AssociatableController
).
You may alternatively define ordering in your Eloquent model:
protected static function boot()
{
parent::boot();
static::addGlobalScope('ordered', function ($query) {
// We only fetch group priority, in order not to have ambiguous
// `id` field which would break e.g. `->where(`id`, `=`, $id)` clause
// in Laravel `EloquentUserProvider`.
$withOrder = \DB::table('users')
->join('user_groups', 'users.user_group_id', '=', 'user_groups.id')
->select('users.*', 'user_groups.priority');
// We use our subselect in place of the `users` table.
$query->from($withOrder, 'users');
// Now we add our orderings.
$query->orderBy('users.priority', 'asc');
// $query->orderBy('users.name', 'asc');
// $query->orderBy('users.login', 'asc');
// etc.
});
}
and then disable the default Nova order-by-recent behavior in your resource with:
protected static function applyOrderings($query, array $orderings)
{
if (empty($orderings)) return $query;
return parent::applyOrderings($query, $orderings);
}
Nova Sortable is open-sourced software licensed under the MIT license.