Таблицы

# Свойства

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $sortColumn = ''; // Поле сортировки по умолчанию
 
protected string $sortDirection = 'DESC'; // Тип сортировки по умолчанию
 
protected int $itemsPerPage = 25; // Количество элементов на странице
 
//...
}

# Кнопки

Для добавления кнопок в таблицу используются ActionButton и методы indexButtons или buttons в ресурсе

public function indexButtons(): array
{
return [
ActionButton::make('Link', '/endpoint'),
];
}

Пример создания кастомных кнопок у индексной таблицы в разделе Recipes

Для массовых действий необходимо добавить метод bulk

public function indexButtons(): array
{
return [
ActionButton::make('Link', '/endpoint')->bulk(),
];
}

Также можно воспользоваться методом buttons, но в таком случае кнопки будут и на всех остальных страницах ресурса

public function buttons(): array
{
return [
ActionButton::make('Link', '/endpoint'),
];
}

# Атрибуты

Через ресурсы модели есть возможность кастомизировать tr и td у таблицы с данными.
Для это необходимо использовать соответствующие методы trAttributes() и tdAttributes(), которым нужно передать замыкание, возвращающее атрибуты для компонента таблица.

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use Closure;
use Illuminate\View\ComponentAttributeBag;
use MoonShine\Fields\Text;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
//...
 
public function trAttributes(): Closure
{
return function (
Model $item,
int $row,
ComponentAttributeBag $attr
): ComponentAttributeBag {
if ($item->id === 1 | $row === 2) {
$attr->setAttributes([
'class' => 'bgc-green'
]);
}
 
return $attr;
};
}
 
public function tdAttributes(): Closure
{
return function (
Model $item,
int $row,
int $cell,
ComponentAttributeBag $attr = null
): ComponentAttributeBag {
if ($cell === 6) {
$attr->setAttributes([
'class' => 'bgc-red'
]);
}
 
return $attr;
};
}
 
//...
}

# Действия по клику

По умолчанию на клик по tr ничего не произойдет, но можно изменить поведение на переход в редактирование, выбор или переход к детальному просмотру

// Свойство ресурса
// ClickAction::SELECT, ClickAction::DETAIL, ClickAction::EDIT
 
protected ?ClickAction $clickAction = ClickAction::SELECT;

# Фиксированная шапка таблицы

Свойство ресурса модели stickyTable позволяет зафиксировать шапку при прокрутке таблицы с большим числом элементов.

namespace App\MoonShine\Resources;
 
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $stickyTable = true;
 
// ...
}

# Простая пагинация

Если вы не планируете отображать общее количество страниц, воспользуйтесь Simple Pagination. Это позволит избежать дополнительных запросов на общее количество записей в базе данных.

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $simplePaginate = true;
 
// ...
}

# Отключение пагинации

Если вы не планируете использовать разбиение на страницы, то его можно отключить.

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $usePagination = false;
 
// ...
}

# Асинхронный режим

Переключить режим без перезагрузки для фильтрации, сортировки и пагинации

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $isAsync = true;
 
// ...
}

# Обновление ряда

У таблицы можно асинхронно обновить ряд, для этого необходимо вызвать событие:

table-row-updated-{{componentName}}-{{row-key}}
  • {{componentName}} - название компонента;
  • {{row-key}} - ключ ряда.

Для добавления события можно воспользоваться классом-помощником:

AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'main-table-{row-id}')
  • {row-id} - shortcode для id текущей записи модели.

Наличие поля ID и асинхронный режим является обязательными.

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Enums\JsEvent;
use MoonShine\Fields\ID;
use MoonShine\Fields\Switcher;
use MoonShine\Fields\Text;
use MoonShine\Fields\Textarea;
use MoonShine\Resources\ModelResource;
use MoonShine\Support\AlpineJs;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $isAsync = true;
 
//...
 
public function fields(): array
{
return [
ID::make(),
Text::make('Title'),
Textarea::make('Body'),
Switcher::make('Active')
->updateOnPreview(
events: [AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'index-table-{row-id}')]
)
];
}
 
//...
}

Также доступен метод withUpdateRow(), который помогает упростить назначение событий:

TableBuilder::make()
->fields([
ID::make()->sortable(),
Text::make('Title'),
Textarea::make('Body'),
Switcher::make('Active')
->withUpdateRow('main-table')
])
->items($this->fetch())
->name('main-table')
->async(),

# Отображение колонок

Можно предоставить пользователям самостоятельно определять какие колонки отображать в таблице, с сохранением выбора. Для этого необходимо у ресурса задать параметр $columnSelection.

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $columnSelection = true;
 
//...
}

Если необходимо исключить поля из выбора, то воспользуйтесь методом columnSelection().

public function columnSelection(bool $active = true)
namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Fields\ID;
use MoonShine\Fields\Text;
use MoonShine\Fields\Textarea;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $columnSelection = true;
 
//...
 
public function fields(): array
{
return [
ID::make()
->columnSelection(false),
Text::make('Title'),
Textarea::make('Body'),
];
}
 
//...
}

# Модификация

Вы можете заменить thead или tbody или tfoot, а также добавить элементы в таблицу в tbody до первого row и после.

thead()
namespace App\MoonShine\Resources;
 
use MoonShine\Fields\Fields;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
// ...
 
public function thead(): ?Closure
{
return static fn(Fields $headFields): string => '<tr><th>Title</th></tr>';
}
}
tbody()
namespace App\MoonShine\Resources;
 
use Illuminate\Support\Collection;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
// ...
 
public function tbody(): ?Closure
{
return static fn(Collection $rows): string => '<tr><td>Content</td></tr>';
}
}
tfoot()
namespace App\MoonShine\Resources;
 
use MoonShine\ActionButtons\ActionButtons;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
// ...
 
public function tfoot(): ?Closure
{
return static fn(ActionButtons $bulkButtons): string => '<tr><td>Footer</td></tr>';
}
}
tbodyBefore()
namespace App\MoonShine\Resources;
 
use Illuminate\Support\Collection;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
// ...
 
public function tbodyBefore(): ?Closure
{
return static fn(Collection $rows): string => '<tr><td>Before</td></tr>';
}
}
tbodyAfter()
namespace App\MoonShine\Resources;
 
use Illuminate\Support\Collection;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
// ...
 
public function tbodyAfter(): ?Closure
{
return static fn(Collection $rows): string => '<tr><td>After</td></tr>';
}
}