Компоненты

TableBuilder

Основы

TableBuilder - инструмент в MoonShine для создания настраиваемых таблиц для отображения данных. Он используется на индексной и детальной CRUD-страницах, а также для полей отношений, таких как HasMany, BelongsToMany, RelationRepeater и поля Json.

use MoonShine\UI\Components\Table\TableBuilder;
 
TableBuilder::make(iterable $fields = [], iterable $items = [])
use MoonShine\UI\Components\Table\TableBuilder;
 
TableBuilder::make(iterable $fields = [], iterable $items = [])
<x-moonshine::table
:columns="[
'#', 'First', 'Last', 'Email'
]"
:values="[
[1, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[2, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[3, fake()->firstName(), fake()->lastName(), fake()->safeEmail()]
]"
/>
 
<x-moonshine::table>
<x-slot:thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Email</th>
<th>Role</th>
<th>Date</th>
<th>Status</th>
<th></th>
</tr>
</x-slot:thead>
 
<x-slot:tbody>
<tr>
<td>1</td>
<td>Ivan Ivanov</td>
<td>ivan@gmail.com</td>
<td>Editor</td>
<td>01.01.2025</td>
<td>
<x-moonshine::badge color="success">Active</x-moonshine::badge>
</td>
<td>
<x-moonshine::layout.flex justify-align="end" without-space class="gap-2">
<x-moonshine::link-button href="/" class="btn-square">
<x-moonshine::icon icon="eye"></x-moonshine::icon>
</x-moonshine::link-button>
 
<x-moonshine::link-button href="/" class="btn-square btn-secondary">
<x-moonshine::icon icon="pencil"></x-moonshine::icon>
</x-moonshine::link-button>
 
<x-moonshine::link-button href="/" class="btn-square btn-error">
<x-moonshine::icon icon="trash"></x-moonshine::icon>
</x-moonshine::link-button>
</x-moonshine::layout.flex>
 
</td>
</tr>
</x-slot:tbody>
<x-slot:tfoot></x-slot:tfoot>
</x-moonshien::table>
<x-moonshine::table
:columns="[
'#', 'First', 'Last', 'Email'
]"
:values="[
[1, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[2, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[3, fake()->firstName(), fake()->lastName(), fake()->safeEmail()]
]"
/>
 
<x-moonshine::table>
<x-slot:thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Email</th>
<th>Role</th>
<th>Date</th>
<th>Status</th>
<th></th>
</tr>
</x-slot:thead>
 
<x-slot:tbody>
<tr>
<td>1</td>
<td>Ivan Ivanov</td>
<td>ivan@gmail.com</td>
<td>Editor</td>
<td>01.01.2025</td>
<td>
<x-moonshine::badge color="success">Active</x-moonshine::badge>
</td>
<td>
<x-moonshine::layout.flex justify-align="end" without-space class="gap-2">
<x-moonshine::link-button href="/" class="btn-square">
<x-moonshine::icon icon="eye"></x-moonshine::icon>
</x-moonshine::link-button>
 
<x-moonshine::link-button href="/" class="btn-square btn-secondary">
<x-moonshine::icon icon="pencil"></x-moonshine::icon>
</x-moonshine::link-button>
 
<x-moonshine::link-button href="/" class="btn-square btn-error">
<x-moonshine::icon icon="trash"></x-moonshine::icon>
</x-moonshine::link-button>
</x-moonshine::layout.flex>
 
</td>
</tr>
</x-slot:tbody>
<x-slot:tfoot></x-slot:tfoot>
</x-moonshien::table>

Основное использование

Пример использования TableBuilder:

TableBuilder::make()
->items([
['id' => 1, 'title' => 'Hello world']
])
->fields([
ID::make()->sortable(),
Text::make('Title'),
])
TableBuilder::make()
->items([
['id' => 1, 'title' => 'Hello world']
])
->fields([
ID::make()->sortable(),
Text::make('Title'),
])

Основные методы

Поля

Поля для TableBuilder упрощают наполнение данными и отображение ячеек таблицы. По умолчанию поля выводятся в режиме "preview". Метод fields() определяет поля таблицы, каждое поле является ячейкой таблицы (td).

->fields([
ID::make()->sortable(),
Text::make('Title'),
])
->fields([
ID::make()->sortable(),
Text::make('Title'),
])

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

->fields([
ID::make()->sortable(),
Text::make('Title')
->customWrapperAttributes(['class' => 'my-class']),
])
->fields([
ID::make()->sortable(),
Text::make('Title')
->customWrapperAttributes(['class' => 'my-class']),
])

Данные

Метод items() устанавливает данные для таблицы.

->items($this->getCollection())
->items($this->getCollection())

Пагинация

Метод paginator() устанавливает пагинатор для таблицы. Необходимо передать объект, реализующий интерфейс MoonShine\Contracts\Core\Paginator\PaginatorContract.

Если необходимо указать пагинатор для QueryBuilder, можно воспользоваться встроенным ModelCaster, как в примере ниже.

->paginator(
(new ModelCaster(Article::class))
->paginatorCast(
Article::query()->paginate()
)
)
->paginator(
(new ModelCaster(Article::class))
->paginatorCast(
Article::query()->paginate()
)
)

Пагинатор также можно указать через метод items().

Упрощенный вид пагинатора

Метод simple() применяет упрощенный стиль пагинации в таблице.

->simple()
->simple()

Кнопки

Метод buttons() добавляет кнопки действий.

->buttons([
ActionButton::make('Delete', fn() => route('name.delete')),
ActionButton::make('Edit', fn() => route('name.edit'))->showInDropdown(),
ActionButton::make('Go to home', fn() => route('home'))->blank()->canSee(fn($data) => $data->active),
ActionButton::make('Mass Delete', fn() => route('name.mass_delete'))->bulk(),
])
->buttons([
ActionButton::make('Delete', fn() => route('name.delete')),
ActionButton::make('Edit', fn() => route('name.edit'))->showInDropdown(),
ActionButton::make('Go to home', fn() => route('home'))->blank()->canSee(fn($data) => $data->active),
ActionButton::make('Mass Delete', fn() => route('name.mass_delete'))->bulk(),
])

Для указания массовых действий над элементами таблицы необходимо у ActionButton указать метод bulk().

->buttons([
ActionButton::make(
'Mass Delete',
fn() => route('name.mass_delete')
)->bulk(),
])
->buttons([
ActionButton::make(
'Mass Delete',
fn() => route('name.mass_delete')
)->bulk(),
])

Если вам необходимо зафиксировать кнопки (sticky), тогда воспользуйтесь методом stickyButtons().

->stickyButtons()
->stickyButtons()

Отображение

Вертикальное отображение

Метод vertical() отображает таблицу в вертикальном формате (используется на DetailPage).

->vertical()
->vertical()

Если вы хотите изменить атрибуты колонок при вертикальном режиме, то воспользуйтесь параметрами title или value.

vertical(null|Closure|int $title = null, null|Closure|int $value = null)
vertical(null|Closure|int $title = null, null|Closure|int $value = null)
  • title - Колонка с заголовком,
  • value - Колонка со значением.
/** @param TableBuilder $component */
public function modifyDetailComponent(ComponentContract $component): ComponentContract
{
return $component->vertical(
title: fn(FieldContract $field, Column $default, TableBuilder $ctx): ComponentContract => $default->columnSpan(2),
value: fn(FieldContract $field, Column $default, TableBuilder $ctx): ComponentContract => $default->columnSpan(10),
);
}
/** @param TableBuilder $component */
public function modifyDetailComponent(ComponentContract $component): ComponentContract
{
return $component->vertical(
title: fn(FieldContract $field, Column $default, TableBuilder $ctx): ComponentContract => $default->columnSpan(2),
value: fn(FieldContract $field, Column $default, TableBuilder $ctx): ComponentContract => $default->columnSpan(10),
);
}

Также можно передать целочисленное значение для указания колонок.

$component->vertical(
title: 2,
value: 10,
)
$component->vertical(
title: 2,
value: 10,
)

Редактируемая таблица

Метод editable() делает таблицу редактируемой. Все поля переводятся в режим defaultMode (режим формы).

->editable()
->editable()

Упрощенный режим

Метод preview() отключает отображение кнопок и сортировок для таблицы.

->preview()
->preview()

С уведомлением "Ничего не найдено"

По умолчанию если у таблицы нет данных, то она будет пустой, но можно вывести сообщение "Пока записей нет". Для этого воспользуйтесь методом withNotFound().

->withNotFound()
->withNotFound()

Кастомизация строк

Поля ускоряют процесс и наполняют таблицу самостоятельно, выстраивая шапку таблицы с заголовками полей и сортировок, тело таблицы с выводом данных через поля и футер таблицы с массовыми действиями. Однако иногда может возникнуть потребность указать строки самостоятельно либо добавить дополнительные. Для этой задачи существуют методы для соответствующих секций таблицы: headRows (thead), rows (tbody), footRows (tfoot).

// tbody
TableBuilder::make()
->rows(
static fn(TableRowsContract $default) => $default->pushRow(
TableCells::make()->pushCell('td content')
)
)
 
// thead
TableBuilder::make()
->headRows(
static fn(TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell('td content')
)
)
 
// tfoot
TableBuilder::make()
->footRows(
static fn(?TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell('td content')
)
)
// tbody
TableBuilder::make()
->rows(
static fn(TableRowsContract $default) => $default->pushRow(
TableCells::make()->pushCell('td content')
)
)
 
// thead
TableBuilder::make()
->headRows(
static fn(TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell('td content')
)
)
 
// tfoot
TableBuilder::make()
->footRows(
static fn(?TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell('td content')
)
)

Обратите внимание, для footRows передается ?TableRowContract и в значении $default будет передано null, если кнопки массовых действий отсутствуют. Значение null можно указывать в списке $items в TableRows::make, оно будет проигнорировано.

TableRows и TableCells - это коллекции компонентов с дополнительным функционалом для быстрого добавления строки или ячейки таблицы.

TableRows::make()->pushRow(
TableCellsContract $cells,
int|string|null $key = null,
?Closure $builder = null
)
TableRows::make()->pushRow(
TableCellsContract $cells,
int|string|null $key = null,
?Closure $builder = null
)
  • $cells - коллекция ячеек,
  • $key - уникальный ключ tr для массовых действий и событий обновления строк таблицы,
  • $builder - доступ к TableBuilder.
TableCells::make()->pushCell(
Closure|string $content,
?int $index = null,
?Closure $builder = null,
array $attributes = []
)
TableCells::make()->pushCell(
Closure|string $content,
?int $index = null,
?Closure $builder = null,
array $attributes = []
)
  • $content - содержимое ячейки,
  • $index - порядковый номер ячейки,
  • $builder - доступ к TableBuilder,
  • $attributes - HTML атрибуты ячейки.

У TableCells также есть дополнительные вспомогательные методы.

Метод pushFields() для быстрой генерации ячеек на основе полей.

TableCells::make()->pushFields(
FieldsContract $fields,
?Closure $builder = null,
int $startIndex = 0
)
TableCells::make()->pushFields(
FieldsContract $fields,
?Closure $builder = null,
int $startIndex = 0
)
  • $fields - коллекция полей,
  • $builder - доступ к TableBuilder,
  • $startIndex - начальный индекс (так как до этого, возможно, уже были добавлены ячейки таблицы).

Также доступны условные методы pushWhen() и pushCellWhen().

Дополнительные возможности

Добавление новых строк

Метод creatable() позволяет добавлять новые строки, делает таблицу динамической.

creatable(
bool $reindex = true,
?int $limit = null,
?string $label = null,
?string $icon = null,
array $attributes = [],
?ActionButtonContract $button = null
)
creatable(
bool $reindex = true,
?int $limit = null,
?string $label = null,
?string $icon = null,
array $attributes = [],
?ActionButtonContract $button = null
)
  • $reindex - режим редактирования с динамическим name,
  • $limit - количество записей, которые можно добавить,
  • $label - название кнопки,
  • $icon - иконка у кнопки,
  • $attributes - дополнительные атрибуты,
  • $button - кастомная кнопка добавления.
->creatable(
reindex: true,
limit: 5,
label: 'Add',
icon: 'plus',
attributes: ['class' => 'my-class']
)
->creatable(
reindex: true,
limit: 5,
label: 'Add',
icon: 'plus',
attributes: ['class' => 'my-class']
)

В режиме добавления необходимо, чтобы последний элемент был пустым (скелет новой записи)!

Если в таблице находятся поля в режиме редактирования с динамическим name, то нужно добавить метод или параметр $reindex.

TableBuilder::make()
->creatable(reindex: true)
 
TableBuilder::make()
->creatable()
->reindex()
TableBuilder::make()
->creatable(reindex: true)
 
TableBuilder::make()
->creatable()
->reindex()

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

->creatable(
button: ActionButton::make('Foo', '#')
)
->creatable(
button: ActionButton::make('Foo', '#')
)

Переиндексация

Метод reindex() позволяет переиндексировать элементы таблицы, всем name атрибутам элементов формы будет добавлен индекс. Пример: Поле Text::make('Title', 'title') на первой строке tr таблицы будет иметь вид <input name="title[1]">. В режиме creatable или removable при добавлении/удалении новой строки все атрибуты name будут переиндексированы с учетом порядкового номера.

->reindex()
->reindex()

Без ключей

Метод withoutKey() заставляет таблицу использовать порядковые индексы вместо уникального ключа строки. Это полезно, когда источник данных может содержать повторяющиеся идентификаторы — например, при работе с BelongsToMany::deduplication(false) или любыми коллекциями, где одна и та же модель должна отображаться несколько раз.

->withoutKey()
->withoutKey()

Сортировка перетаскиванием

Метод reorderable() добавляет возможность сортировки строк перетаскиванием.

->reorderable(url: '/reorder-url', key: 'id', group: 'group-name')
->reorderable(url: '/reorder-url', key: 'id', group: 'group-name')
  • $url - URL-обработчика,
  • $key - ключ элемента,
  • $group - группировка (если требуется).

Метод sticky() делает заголовок таблицы фиксированным.

->sticky()
->sticky()

Выбор колонок

Метод columnSelection() добавляет возможность выбора отображаемых колонок.

->columnSelection()
->columnSelection()

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

TableBuilder::make()
->fields([
Text::make('Title')
->columnSelection(false),
Text::make('Text')
])
->columnSelection()
TableBuilder::make()
->fields([
Text::make('Title')
->columnSelection(false),
Text::make('Text')
])
->columnSelection()

При использовании columnSelection параметр name компонента TableBuilder должен быть уникальным для всех страниц. Это связано с тем, что данные сохраняются в localStorage на основе значения name компонента.

Метод searchable() добавляет функцию поиска по таблице:

->searchable()
->searchable()

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

Метод clickAction() задает действие при клике на строку. В примере ниже при клике на строку таблицы произойдет клик на кнопку редактирования.

->clickAction(ClickAction::EDIT)
->clickAction(ClickAction::EDIT)

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

->clickAction(ClickAction::EDIT, '.edit-button')
->clickAction(ClickAction::EDIT, '.edit-button')

Типы ClickAction:

  • ClickAction::SELECT - выбор строки для массовых действий,
  • ClickAction::EDIT - переход в редактирование,
  • ClickAction::DETAIL - переход в детальный просмотр.

Сохранение состояния в URL

Метод pushState() сохраняет состояние таблицы в URL.

->pushState()
->pushState()

Модификация чекбокса массовых действий

Метод modifyRowCheckbox() позволяет модифицировать чекбокс массовых действий. Пример ниже демонстрирует выбор активного чекбокса по умолчанию.

->modifyRowCheckbox(
fn(Checkbox $checkbox, DataWrapperContract $data, TableBuilder $ctx) => $data->getKey() === 2
? $checkbox->customAttributes(['checked' => true])
: $checkbox
)
->modifyRowCheckbox(
fn(Checkbox $checkbox, DataWrapperContract $data, TableBuilder $ctx) => $data->getKey() === 2
? $checkbox->customAttributes(['checked' => true])
: $checkbox
)

Слоты

Вы можете добавить контент над таблицей слева или справа с помощью методов topLeft() и topRight().

TableBuilder::make()
// ...
->topLeft(function (): array {
return [];
})
->topRight(function (): array {
return [
Div::make([
// ...
])
];
})
TableBuilder::make()
// ...
->topLeft(function (): array {
return [];
})
->topRight(function (): array {
return [
Div::make([
// ...
])
];
})

Фильтры через FormBuilder

С помощью метода withFilters() вы можете добавить FormBuilder с полями для фильтрации данных в таблице. После отправки формы данные будут загружены заново.

->withFilters(formName: 'dashboard-form')
->withFilters(formName: 'dashboard-form')
  • $formName - Уникальное имя формы.

Логику применения фильтров к данным в таблице необходимо реализовать самостоятельно.

Пример с асинхронной загрузкой:

FormBuilder::make()
->name('dashboard-form')
->fields([
Date::make('Date')
])
->dispatchEvent([
AlpineJs::event(
JsEvent::TABLE_UPDATED, 'dashboard-table'
)
]),
 
TableBuilder::make()
->name('dashboard-table')
->withFilters('dashboard-form')
->async()
->fields([
Text::make('Title')->sortable()
])
->items([
['title' => fake()->word()]
])
FormBuilder::make()
->name('dashboard-form')
->fields([
Date::make('Date')
])
->dispatchEvent([
AlpineJs::event(
JsEvent::TABLE_UPDATED, 'dashboard-table'
)
]),
 
TableBuilder::make()
->name('dashboard-table')
->withFilters('dashboard-form')
->async()
->fields([
Text::make('Title')->sortable()
])
->items([
['title' => fake()->word()]
])

Префикс query-параметров

Вы можете задать префикс для query-параметров пагинации и сортировки. Это удобно, когда на странице используется несколько компонентов TableBuilder, и каждому нужны собственные параметры запроса, чтобы избежать конфликтов между ними.

->queryParamPrefix(prefix: 'users_')
->queryParamPrefix(prefix: 'users_')
  • $prefix - Строковый префикс.

Настройка атрибутов

TableBuilder предоставляет методы для настройки HTML-атрибутов.

TableBuilder::make()
->trAttributes(fn(?DataWrapperContract $data, int $row): array => ['class' => $row % 2 ? 'bg-gray-100' : ''])
->tdAttributes(fn(?DataWrapperContract $data, int $row, int $cell): array => ['class' => $cell === 0 ? 'font-bold' : ''])
->headAttributes(['class' => 'bg-blue-500 text-white'])
->bodyAttributes(['class' => 'text-sm'])
->footAttributes(['class' => 'bg-gray-200'])
->customAttributes(['class' => 'custom-table'])
TableBuilder::make()
->trAttributes(fn(?DataWrapperContract $data, int $row): array => ['class' => $row % 2 ? 'bg-gray-100' : ''])
->tdAttributes(fn(?DataWrapperContract $data, int $row, int $cell): array => ['class' => $cell === 0 ? 'font-bold' : ''])
->headAttributes(['class' => 'bg-blue-500 text-white'])
->bodyAttributes(['class' => 'text-sm'])
->footAttributes(['class' => 'bg-gray-200'])
->customAttributes(['class' => 'custom-table'])

Асинхронная загрузка

Метод async() настраивает асинхронную загрузку таблицы.

Метод async() должен быть после метода name.

->async(
Closure|string|null $url = null,
string|array|null $events = null,
?AsyncCallback $callback = null,
)
->async(
Closure|string|null $url = null,
string|array|null $events = null,
?AsyncCallback $callback = null,
)
  • $url - URL асинхронного запроса (в ответе необходимо вернуть TableBuilder),
  • $events - события, которые будут вызваны после успешного ответа,
  • $callback - JS callback, который можно добавить как обертку ответа.

После успешного запроса можно вызвать события, добавив параметр $events.

use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
 
TableBuilder::make()
->name('crud')
->async(events: [
AlpineJs::event(JsEvent::FORM_RESET, 'main-form'),
AlpineJs::event(JsEvent::TOAST, params: ['text' => 'Success', 'type' => 'success']),
])
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
 
TableBuilder::make()
->name('crud')
->async(events: [
AlpineJs::event(JsEvent::FORM_RESET, 'main-form'),
AlpineJs::event(JsEvent::TOAST, params: ['text' => 'Success', 'type' => 'success']),
])

Список событий для TableBuilder:

  • JsEvent::TABLE_UPDATED - обновление таблицы,
  • JsEvent::TABLE_REINDEX - реиндексация таблицы (см. reindex()),
  • JsEvent::TABLE_ROW_UPDATED - обновление строки таблицы (AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, "{component-name}")),
  • JsEvent::TABLE_ROW_ADDED - добавление новой клонированной строки,
  • JsEvent::TABLE_EMPTY_ROW_ADDED - добавление новой строки.

Для получения дополнительной информации о js событиях обратитесь к разделу Events.

Все параметры метода async() являются опциональными, и по умолчанию TableBuilder автоматически укажет URL на основе текущей страницы.

В процессе использования TableBuilder в режиме async может возникнуть задача, когда вы используете его вне админ-панели на страницах, не объявленных в системе MoonShine. Тогда вам потребуется указать собственный URL и реализовать ответ с HTML таблицей. Давайте рассмотрим пример реализации:

TableBuilder::make()
->name('my-table')
->async(
route('undefined-page.component', [
'_namespace' => self::class,
'_component_name' => 'my-table'
])
)
TableBuilder::make()
->name('my-table')
->async(
route('undefined-page.component', [
'_namespace' => self::class,
'_component_name' => 'my-table'
])
)

Controller

namespace App\MoonShine\Controllers;
 
use Illuminate\Contracts\View\View;
use MoonShine\Contracts\Core\DependencyInjection\CrudRequestContract;
use MoonShine\Laravel\Http\Controllers\MoonShineController;
 
final class UndefinedPageController extends MoonShineController
{
public function component(CrudRequestContract $request): View
{
$page = app($request->input('_namespace'));
 
$component = $page->getComponents()->findByName(
$request->getComponentName()
);
 
return $component->render();
}
}
namespace App\MoonShine\Controllers;
 
use Illuminate\Contracts\View\View;
use MoonShine\Contracts\Core\DependencyInjection\CrudRequestContract;
use MoonShine\Laravel\Http\Controllers\MoonShineController;
 
final class UndefinedPageController extends MoonShineController
{
public function component(CrudRequestContract $request): View
{
$page = app($request->input('_namespace'));
 
$component = $page->getComponents()->findByName(
$request->getComponentName()
);
 
return $component->render();
}
}

Lazy и whenAsync методы

Если вам необходимо отправить запрос на обновление компонента TableBuilder сразу при загрузке страницы, то нужно добавить метод lazy(). Также методы lazy() и whenAsync() в сочетании могут решить задачу ленивой загрузки данных или загрузки данных из внешнего источника.

TableBuilder::make()
->name('dashboard-table')
->fields([
ID::make(),
Slug::make('Slug'),
Text::make('Title'),
Preview::make('Image')->image()
])
->async()
->lazy()
->whenAsync(
fn(TableBuilder $table) => $table->items(
Http::get('https://jsonplaceholder.org/posts')->json()
)
),
TableBuilder::make()
->name('dashboard-table')
->fields([
ID::make(),
Slug::make('Slug'),
Text::make('Title'),
Preview::make('Image')->image()
])
->async()
->lazy()
->whenAsync(
fn(TableBuilder $table) => $table->items(
Http::get('https://jsonplaceholder.org/posts')->json()
)
),

Метод whenAsync() проверяет, является ли текущий запрос асинхронным для получения текущего компонента TableBuilder. Пример взаимодействия с методами, где загрузка таблицы происходит по нажатию на кнопку:

ActionButton::make('Reload')
->async(events: [AlpineJs::event(JsEvent::TABLE_UPDATED, 'my-table')]),
 
TableBuilder::make()
->name('my-table')
->fields([
ID::make(),
Slug::make('Slug'),
Text::make('Title'),
Preview::make('Image')->image()
])
->async()
->lazy()
->whenAsync(
fn(TableBuilder $table) => $table->items(
Http::get('https://jsonplaceholder.org/posts')->json()
)
)
->withNotFound(),
ActionButton::make('Reload')
->async(events: [AlpineJs::event(JsEvent::TABLE_UPDATED, 'my-table')]),
 
TableBuilder::make()
->name('my-table')
->fields([
ID::make(),
Slug::make('Slug'),
Text::make('Title'),
Preview::make('Image')->image()
])
->async()
->lazy()
->whenAsync(
fn(TableBuilder $table) => $table->items(
Http::get('https://jsonplaceholder.org/posts')->json()
)
)
->withNotFound(),

Приведение к типу

Если вы используете данные в таблице без cast, необходимо указать, что в ваших данных является ключом. В противном случае некоторые возможности, такие как bulk-операции, работать не будут.

Пример:

TableBuilder::make()
->castKeyName('id')
->name('my-table')
->fields([
ID::make(),
Text::make('Title')
])
->items([
['id' => 3,'title' => 'Hello world']
])
->buttons([
ActionButton::make('Mass Delete')
->bulk()
]),
TableBuilder::make()
->castKeyName('id')
->name('my-table')
->fields([
ID::make(),
Text::make('Title')
])
->items([
['id' => 3,'title' => 'Hello world']
])
->buttons([
ActionButton::make('Mass Delete')
->bulk()
]),

Метод cast() служит для приведения значений таблицы к определенному типу. Так как по умолчанию поля работают с примитивными типами:

use MoonShine\Laravel\TypeCasts\ModelCaster;
 
TableBuilder::make()
->cast(new ModelCaster(User::class))
use MoonShine\Laravel\TypeCasts\ModelCaster;
 
TableBuilder::make()
->cast(new ModelCaster(User::class))

В этом примере мы привели данные к формату модели User с использованием ModelCaster.

За более подробной информацией обратитесь к разделу TypeCasts.

Использование в blade

Основы

Стилизованные таблицы можно создавать с помощью компонента moonshine::table.

<x-moonshine::table
:columns="[
'#', 'First', 'Last', 'Email'
]"
:values="[
[1, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[2, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[3, fake()->firstName(), fake()->lastName(), fake()->safeEmail()]
]"
/>
<x-moonshine::table
:columns="[
'#', 'First', 'Last', 'Email'
]"
:values="[
[1, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[2, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[3, fake()->firstName(), fake()->lastName(), fake()->safeEmail()]
]"
/>

Упрощенный вид

Параметр simple позволяет создавать упрощенного вида таблицы.

<x-moonshine::table
:simple="true"
:columns="[
'#', 'First', 'Last', 'Email'
]"
:values="[
[1, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[2, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[3, fake()->firstName(), fake()->lastName(), fake()->safeEmail()]
]"
/>
<x-moonshine::table
:simple="true"
:columns="[
'#', 'First', 'Last', 'Email'
]"
:values="[
[1, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[2, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[3, fake()->firstName(), fake()->lastName(), fake()->safeEmail()]
]"
/>

Фиксированный заголовок

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

<x-moonshine::table
:sticky="true"
:columns="[
'#', 'First', 'Last', 'Email'
]"
:values="[
[1, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[2, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[3, fake()->firstName(), fake()->lastName(), fake()->safeEmail()]
]"
/>
<x-moonshine::table
:sticky="true"
:columns="[
'#', 'First', 'Last', 'Email'
]"
:values="[
[1, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[2, fake()->firstName(), fake()->lastName(), fake()->safeEmail()],
[3, fake()->firstName(), fake()->lastName(), fake()->safeEmail()]
]"
/>

С уведомлением "Ничего не найдено"

Параметр notfound позволяет выводить сообщение при отсутствии элементов таблицы.

<x-moonshine::table
:columns="[
'#', 'First', 'Last', 'Email'
]"
:notfound="true"
/>
<x-moonshine::table
:columns="[
'#', 'First', 'Last', 'Email'
]"
:notfound="true"
/>

Для перевода или изменения текста уведомления необходимо задать параметр translates.

<x-moonshine::table
:columns="[
'#', 'First', 'Last', 'Email'
]"
:notfound="true"
:translates="['notfound' => __('moonshine.ui.notfound')]"
/>
<x-moonshine::table
:columns="[
'#', 'First', 'Last', 'Email'
]"
:notfound="true"
:translates="['notfound' => __('moonshine.ui.notfound')]"
/>

Слоты

Таблицу можно сформировать с использованием слотов.

<x-moonshine::table>
<x-slot:thead class="text-center">
<th colspan="4">Header</th>
</x-slot:thead>
<x-slot:tbody>
<tr>
<th>1</th>
<th>{{ fake()->firstName() }}</th>
<th>{{ fake()->lastName() }}</th>
<th>{{ fake()->safeEmail() }}</th>
</tr>
<tr>
<th>2</th>
<th>{{ fake()->firstName() }}</th>
<th>{{ fake()->lastName() }}</th>
<th>{{ fake()->safeEmail() }}</th>
</tr>
<tr>
<th>3</th>
<th>{{ fake()->firstName() }}</th>
<th>{{ fake()->lastName() }}</th>
<th>{{ fake()->safeEmail() }}</th>
</tr>
</x-slot:tbody>
<x-slot:tfoot class="text-center">
<td colspan="4">Footer</td>
</x-slot:tfoot>
</x-moonshine::table>
<x-moonshine::table>
<x-slot:thead class="text-center">
<th colspan="4">Header</th>
</x-slot:thead>
<x-slot:tbody>
<tr>
<th>1</th>
<th>{{ fake()->firstName() }}</th>
<th>{{ fake()->lastName() }}</th>
<th>{{ fake()->safeEmail() }}</th>
</tr>
<tr>
<th>2</th>
<th>{{ fake()->firstName() }}</th>
<th>{{ fake()->lastName() }}</th>
<th>{{ fake()->safeEmail() }}</th>
</tr>
<tr>
<th>3</th>
<th>{{ fake()->firstName() }}</th>
<th>{{ fake()->lastName() }}</th>
<th>{{ fake()->safeEmail() }}</th>
</tr>
</x-slot:tbody>
<x-slot:tfoot class="text-center">
<td colspan="4">Footer</td>
</x-slot:tfoot>
</x-moonshine::table>

Стилизация

Для стилизации таблицы есть предустановленные классы, которые можно использовать для tr / td.

Доступные классы:

bgc-primary bgc-secondary bgc-success bgc-warning bgc-error bgc-info bgc-purple bgc-pink bgc-blue bgc-green bgc-yellow bgc-red bgc-gray

<x-moonshine::table>
<x-slot:thead class="bgc-secondary text-center">
<th colspan="3">Header</th>
</x-slot:thead>
<x-slot:tbody>
<tr>
<th class="bgc-pink">{{ fake()->firstName() }}</th>
<th class="bgc-gray">{{ fake()->lastName() }}</th>
<th class="bgc-purple">{{ fake()->safeEmail() }}</th>
</tr>
<tr>
<th class="bgc-green">{{ fake()->firstName() }}</th>
<th class="bgc-red">{{ fake()->lastName() }}</th>
<th class="bgc-yellow">{{ fake()->safeEmail() }}</th>
</tr>
</x-slot:tbody>
</x-moonshine::table>
<x-moonshine::table>
<x-slot:thead class="bgc-secondary text-center">
<th colspan="3">Header</th>
</x-slot:thead>
<x-slot:tbody>
<tr>
<th class="bgc-pink">{{ fake()->firstName() }}</th>
<th class="bgc-gray">{{ fake()->lastName() }}</th>
<th class="bgc-purple">{{ fake()->safeEmail() }}</th>
</tr>
<tr>
<th class="bgc-green">{{ fake()->firstName() }}</th>
<th class="bgc-red">{{ fake()->lastName() }}</th>
<th class="bgc-yellow">{{ fake()->safeEmail() }}</th>
</tr>
</x-slot:tbody>
</x-moonshine::table>

Состояние загрузки

Для включения и выключения режима скелетона в таблице используйте метод sceleton().

->skeleton(true|false);
->skeleton(true|false);

Для включения и выключения режима спиннера в таблице используйте метод loader().

->loader(true|false);
->loader(true|false);

TableBuilder в MoonShine предоставляет широкий спектр возможностей для создания гибких и функциональных таблиц в административной панели.