- Основы
- Сортировка
- Кнопки
- Атрибуты
- Действия по клику
- Фиксированная шапка таблицы
- Отображение колонок
- Sticky ячейки
- Пагинация
- Асинхронный режим
- Lazy режим
- Модификаторы
Основы
В CrudResource
(ModelResource
) на страницах indexPage
, а также DetailPage
для отображения основных данных используется TableBuilder
,
поэтому мы рекомендуем вам также изучить раздел документации TableBuilder.
Сортировка
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:4]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;use MoonShine\Support\Enums\SortDirection;class PostResource extends ModelResource{// Поле сортировки по умолчаниюprotected string $sortColumn = 'created_at';// Тип сортировки по умолчаниюprotected SortDirection $sortDirection = SortDirection::DESC;// ...}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:4]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;use MoonShine\Support\Enums\SortDirection;class PostResource extends ModelResource{// Поле сортировки по умолчаниюprotected string $sortColumn = 'created_at';// Тип сортировки по умолчаниюprotected SortDirection $sortDirection = SortDirection::DESC;// ...}
Кнопки
Для добавления кнопок в таблицу используются ActionButton
и методы indexButtons()
, а также detailButtons()
для детальной страницы.
После основных:
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:2]use MoonShine\Support\ListOf;use MoonShine\UI\Components\ActionButton;protected function indexButtons(): ListOf{return parent::indexButtons()->add(ActionButton::make('Link', '/endpoint'));}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:2]use MoonShine\Support\ListOf;use MoonShine\UI\Components\ActionButton;protected function indexButtons(): ListOf{return parent::indexButtons()->add(ActionButton::make('Link', '/endpoint'));}
До основных:
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:2]use MoonShine\Support\ListOf;use MoonShine\UI\Components\ActionButton;protected function indexButtons(): ListOf{return parent::indexButtons()->prepend(ActionButton::make('Link', '/endpoint'));}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:2]use MoonShine\Support\ListOf;use MoonShine\UI\Components\ActionButton;protected function indexButtons(): ListOf{return parent::indexButtons()->prepend(ActionButton::make('Link', '/endpoint'));}
Убрать кнопку удаления:
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:2]use MoonShine\Support\ListOf;use MoonShine\UI\Components\ActionButton;protected function indexButtons(): ListOf{return parent::indexButtons()->except(fn(ActionButton $btn) => $btn->getName() === 'resource-delete-button');}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:2]use MoonShine\Support\ListOf;use MoonShine\UI\Components\ActionButton;protected function indexButtons(): ListOf{return parent::indexButtons()->except(fn(ActionButton $btn) => $btn->getName() === 'resource-delete-button');}
Названия стандартных кнопок для таблицы:
- resource-detail-button,
- resource-edit-button,
- resource-delete-button,
- mass-delete-button.
Также можно глобально отключить любые действия с ресурсом (см. активные действия.
Очистить набор кнопок и добавить свою:
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:2]use MoonShine\Support\ListOf;use MoonShine\UI\Components\ActionButton;protected function indexButtons(): ListOf{parent::indexButtons()->empty()->add(ActionButton::make('Link', '/endpoint'));}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:2]use MoonShine\Support\ListOf;use MoonShine\UI\Components\ActionButton;protected function indexButtons(): ListOf{parent::indexButtons()->empty()->add(ActionButton::make('Link', '/endpoint'));}
Такой же подход используется и для таблицы на детальной страницы, только через метод detailButtons()
.
Для массовых действий необходимо добавить метод bulk()
.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:2]use MoonShine\Support\ListOf;use MoonShine\UI\Components\ActionButton;protected function indexButtons(): ListOf{return parent::indexButtons()->add(ActionButton::make('Link', '/endpoint')->bulk());}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:2]use MoonShine\Support\ListOf;use MoonShine\UI\Components\ActionButton;protected function indexButtons(): ListOf{return parent::indexButtons()->add(ActionButton::make('Link', '/endpoint')->bulk());}
По умолчанию все кнопки в таблице выводятся в строку, но вы можете изменить поведение и вывести их через выпадающий список.
Для этого в ресурсе измените свойство $indexButtonsInDropdown
:
class PostResource extends ModelResource{protected bool $indexButtonsInDropdown = true;// ...}
class PostResource extends ModelResource{protected bool $indexButtonsInDropdown = true;// ...}
Атрибуты
Чтобы добавить атрибуты для td
элемента таблицы, можно воспользоваться методом customWrapperAttributes()
у поля, которое представляет нужную вам ячейку.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\UI\Fields\Text;protected function indexFields(): iterable{return [// ...Text::make('Title')->customWrapperAttributes(['width' => '20%']);];}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\UI\Fields\Text;protected function indexFields(): iterable{return [// ...Text::make('Title')->customWrapperAttributes(['width' => '20%']);];}
Также есть возможность кастомизировать tr
и td
у таблицы с данными через ресурс.
Для этого необходимо использовать соответствующие методы trAttributes()
и tdAttributes()
,
которым нужно передать замыкание, возвращающее массив атрибутов для компонента таблицы.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:6]namespace App\MoonShine\Resources;use Closure;use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;use MoonShine\Laravel\Resources\ModelResource;use MoonShine\UI\Fields\Text;class PostResource extends ModelResource{// ...protected function tdAttributes(): Closure{return fn(?DataWrapperContract $data, int $row, int $cell) => ['width' => '20%'];}protected function trAttributes(): Closure{return fn(?DataWrapperContract $data, int $row) => ['data-tr' => $row];}}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:6]namespace App\MoonShine\Resources;use Closure;use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;use MoonShine\Laravel\Resources\ModelResource;use MoonShine\UI\Fields\Text;class PostResource extends ModelResource{// ...protected function tdAttributes(): Closure{return fn(?DataWrapperContract $data, int $row, int $cell) => ['width' => '20%'];}protected function trAttributes(): Closure{return fn(?DataWrapperContract $data, int $row) => ['data-tr' => $row];}}
Действия по клику
По умолчанию на клик по tr
ничего не произойдет, но можно изменить поведение на переход в редактирование, выбор или переход к детальному просмотру.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\Support\Enums\ClickAction;// ClickAction::SELECT, ClickAction::DETAIL, ClickAction::EDITprotected ?ClickAction $clickAction = ClickAction::SELECT;
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\Support\Enums\ClickAction;// ClickAction::SELECT, ClickAction::DETAIL, ClickAction::EDITprotected ?ClickAction $clickAction = ClickAction::SELECT;
Фиксированная шапка таблицы
Свойство ресурса модели stickyTable
позволяет зафиксировать шапку при прокрутке таблицы с большим числом элементов.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravle\Resources\ModelResource;class PostResource extends ModelResource{protected bool $stickyTable = true;// ...}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravle\Resources\ModelResource;class PostResource extends ModelResource{protected bool $stickyTable = true;// ...}
Отображение колонок
Можно предоставить пользователям самостоятельно определять какие колонки отображать в таблице, с сохранением выбора.
Для этого необходимо у ресурса задать параметр $columnSelection
.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $columnSelection = true;// ...}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $columnSelection = true;// ...}
Если необходимо исключить поля из выбора, то воспользуйтесь методом columnSelection()
.
columnSelection(bool $active = true,bool $hideOnInit = false)
columnSelection(bool $active = true,bool $hideOnInit = false)
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:6]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;use MoonShine\UI\Fields\ID;use MoonShine\UI\Fields\Text;use MoonShine\UI\Fields\Textarea;class PostResource extends ModelResource{protected bool $columnSelection = true;// ...protected function indexFields(): iterable{return [ID::make()->columnSelection(false),Text::make('Title'),Textarea::make('Body'),];}}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:6]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;use MoonShine\UI\Fields\ID;use MoonShine\UI\Fields\Text;use MoonShine\UI\Fields\Textarea;class PostResource extends ModelResource{protected bool $columnSelection = true;// ...protected function indexFields(): iterable{return [ID::make()->columnSelection(false),Text::make('Title'),Textarea::make('Body'),];}}
Если необходимо скрыть поле по умолчанию:
->columnSelection(hideOnInit: true)
->columnSelection(hideOnInit: true)
Sticky ячейки
Вы можете фиксировать ячейки при больших таблицах, подойдет для колонок ID и кнопок.
Чтобы зафиксировать кнопки в таблице, переключите ресурс в режим stickyButtons
.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $stickyButtons = true;// ...}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $stickyButtons = true;// ...}
Для фиксации колонки вызовите у поля метод sticky()
.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\UI\Fields\ID;protected function indexFields(): iterable{return [ID::make()->sticky(),];}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\UI\Fields\ID;protected function indexFields(): iterable{return [ID::make()->sticky(),];}
Пагинация
Для изменения количества элементов на странице воспользуйтесь свойством $itemsPerPage
.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected int $itemsPerPage = 25;// ...}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected int $itemsPerPage = 25;// ...}
Курсорная
При большом объеме данных наилучшим решение будет использовать курсорную пагинацию.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $cursorPaginate = true;// ...}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $cursorPaginate = true;// ...}
Упрощенная
Если вы не планируете отображать общее количество страниц, воспользуйтесь Simple Pagination
.
Это позволит избежать дополнительных запросов на общее количество записей в базе данных.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $simplePaginate = true;// ...}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $simplePaginate = true;// ...}
Отключение пагинации
Если вы не планируете использовать разбиение на страницы, то его можно отключить.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $usePagination = false;// ...}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $usePagination = false;// ...}
Асинхронный режим
В ресурсе асинхронный режим используется по умолчанию.
Такой режим дает возможность использовать пагинацию, фильтрацию и сортировку без перезагрузки страницы.
Но если вы хотите отключить асинхронный режим, то воспользуйтесь свойством $isAsync
.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $isAsync = false;// ...}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:3]namespace App\MoonShine\Resources;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $isAsync = false;// ...}
Обновление ряда
У таблицы можно асинхронно обновить ряд, для этого необходимо вызвать событие:
table-row-updated-{{componentName}}-{{row-id}}
table-row-updated-{{componentName}}-{{row-id}}
{{componentName}}
- название компонента;{{row-id}}
- ключ элемента ряда
Для добавления события можно воспользоваться классом-помощником:
AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'main-table-{row-id}')
AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'main-table-{row-id}')
{row-id}
- shortcode для id текущей записи модели.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:8]namespace App\MoonShine\Resources;use MoonShine\UI\Fields\ID;use MoonShine\UI\Fields\Switcher;use MoonShine\UI\Fields\Text;use MoonShine\Laravel\Resources\ModelResource;use MoonShine\Support\AlpineJs;use MoonShine\Support\Enums\JsEvent;class PostResource extends ModelResource{// ...protected function indexFields(): iterable{return [ID::make(),Text::make('Title'),Switcher::make('Active')->updateOnPreview(events: [AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, $this->getListComponentNameWithRow())])];}}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:8]namespace App\MoonShine\Resources;use MoonShine\UI\Fields\ID;use MoonShine\UI\Fields\Switcher;use MoonShine\UI\Fields\Text;use MoonShine\Laravel\Resources\ModelResource;use MoonShine\Support\AlpineJs;use MoonShine\Support\Enums\JsEvent;class PostResource extends ModelResource{// ...protected function indexFields(): iterable{return [ID::make(),Text::make('Title'),Switcher::make('Active')->updateOnPreview(events: [AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, $this->getListComponentNameWithRow())])];}}
Также пример ответа с событием.
public function softDelete(MoonShineRequest $request): MoonShineJsonResponse{$item = $request->getResource()->getItem();$item->delete();return MoonShineJsonResponse::make()->events([AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, $this->getListComponentNameWithRow($item->getKey()))])->toast('Success');}
public function softDelete(MoonShineRequest $request): MoonShineJsonResponse{$item = $request->getResource()->getItem();$item->delete();return MoonShineJsonResponse::make()->events([AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, $this->getListComponentNameWithRow($item->getKey()))])->toast('Success');}
Также доступен метод withUpdateRow()
, который помогает упростить назначение событий.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:6]namespace App\MoonShine\Resources;use MoonShine\UI\Fields\ID;use MoonShine\UI\Fields\Switcher;use MoonShine\UI\Fields\Text;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{// ...protected function indexFields(): iterable{return [ID::make(),Text::make('Title'),Switcher::make('Active')->withUpdateRow($this->getListComponentName())];}}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:6]namespace App\MoonShine\Resources;use MoonShine\UI\Fields\ID;use MoonShine\UI\Fields\Switcher;use MoonShine\UI\Fields\Text;use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{// ...protected function indexFields(): iterable{return [ID::make(),Text::make('Title'),Switcher::make('Active')->withUpdateRow($this->getListComponentName())];}}
Lazy режим
Если необходимо отобразить страницу без ожидания загрузки данных, а затем отправить запрос для получения данных таблицы, используйте режим Lazy.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $isLazy = true;}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\Laravel\Resources\ModelResource;class PostResource extends ModelResource{protected bool $isLazy = true;}
Модификаторы
Компоненты
Вы можете полностью заменить или модифицировать TableBuilder
ресурса для индексной и детальной страницы.
Для этого воспользуйтесь методами modifyListComponent()
или modifyDetailComponent()
.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\Contracts\UI\ComponentContract;public function modifyListComponent(ComponentContract $component): ComponentContract{return parent::modifyListComponent($component)->customAttributes(['data-my-attr' => 'value']);}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\Contracts\UI\ComponentContract;public function modifyListComponent(ComponentContract $component): ComponentContract{return parent::modifyListComponent($component)->customAttributes(['data-my-attr' => 'value']);}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\Contracts\UI\ComponentContract;public function modifyDetailComponent(ComponentContract $component): ComponentContract{return parent::modifyDetailComponent($component)->customAttributes(['data-my-attr' => 'value']);}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:1]use MoonShine\Contracts\UI\ComponentContract;public function modifyDetailComponent(ComponentContract $component): ComponentContract{return parent::modifyDetailComponent($component)->customAttributes(['data-my-attr' => 'value']);}
Элементы thead, tbody, tfoot
Если вам недостаточно просто автоматически выводить поля в thead
, tbody
и tfoot
,
то вы можете переопределить или дополнить эту логику на основе методов ресурса thead()
, tbody()
, tfoot()
.
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:5]use Closure;use MoonShine\Contracts\UI\Collection\TableRowsContract;use MoonShine\Contracts\UI\TableRowContract;use MoonShine\UI\Collections\TableCells;use MoonShine\UI\Collections\TableRows;protected function thead(): null|TableRowsContract|Closure{return static fn(TableRowContract $default) => TableRows::make([$default])->pushRow(TableCells::make()->pushCell('td content'));}protected function tbody(): null|TableRowsContract|Closure{return static fn(TableRowsContract $default) => $default->pushRow(TableCells::make()->pushCell('td content'));}protected function tfoot(): null|TableRowsContract|Closure{return static fn(?TableRowContract $default) => TableRows::make([$default])->pushRow(TableCells::make()->pushCell('td content'));}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:5]use Closure;use MoonShine\Contracts\UI\Collection\TableRowsContract;use MoonShine\Contracts\UI\TableRowContract;use MoonShine\UI\Collections\TableCells;use MoonShine\UI\Collections\TableRows;protected function thead(): null|TableRowsContract|Closure{return static fn(TableRowContract $default) => TableRows::make([$default])->pushRow(TableCells::make()->pushCell('td content'));}protected function tbody(): null|TableRowsContract|Closure{return static fn(TableRowsContract $default) => $default->pushRow(TableCells::make()->pushCell('td content'));}protected function tfoot(): null|TableRowsContract|Closure{return static fn(?TableRowContract $default) => TableRows::make([$default])->pushRow(TableCells::make()->pushCell('td content'));}
Пример добавления строки в tfoot
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:7]use Closure;use MoonShine\Contracts\UI\Collection\TableRowsContract;use MoonShine\Contracts\UI\TableRowContract;use MoonShine\UI\Collections\TableCells;use MoonShine\UI\Collections\TableRows;use MoonShine\UI\Components\Table\TableBuilder;use MoonShine\UI\Components\Table\TableRow;protected function tfoot(): null|TableRowsContract|Closure{return static function(?TableRowContract $default, TableBuilder $table) {$cells = TableCells::make();$cells->pushCell('Balance:');$cells->pushCell('$1000');return TableRows::make([TableRow::make($cells), $default]);};}
// torchlight! {"summaryCollapsedIndicator": "namespaces"}// [tl! collapse:7]use Closure;use MoonShine\Contracts\UI\Collection\TableRowsContract;use MoonShine\Contracts\UI\TableRowContract;use MoonShine\UI\Collections\TableCells;use MoonShine\UI\Collections\TableRows;use MoonShine\UI\Components\Table\TableBuilder;use MoonShine\UI\Components\Table\TableRow;protected function tfoot(): null|TableRowsContract|Closure{return static function(?TableRowContract $default, TableBuilder $table) {$cells = TableCells::make();$cells->pushCell('Balance:');$cells->pushCell('$1000');return TableRows::make([TableRow::make($cells), $default]);};}
Вы можете использовать листинг компонент вне ресурса, но вы должны иметь представление, что он из себя представляет.
app(MoonShineUserResource::class)->getIndexPage()->getListComponent(withoutFragment: false)