- Основы
- Открытие в новом окне
- Иконка
- Цвет
- Бейдж
- onClick
- Модальное окно
- Подтверждение
- Offcanvas
- Группировка
- Массовые действия
- Асинхронный режим
- Отправка событий
- Наполнение данными
Основы
Когда вам нужно добавить кнопку с определенным действием, на помощь приходят ActionButton
.
В MoonShine они уже используются - в формах, таблицах, на страницах.
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;make(Closure|string $label,Closure|string $url = '#',?DataWrapperContract $data = null,)
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;make(Closure|string $label,Closure|string $url = '#',?DataWrapperContract $data = null,)
label
- текст кнопки,url
- URL ссылки кнопки,data
- опциональные данные кнопки, доступные в замыканиях.
use MoonShine\UI\Components\ActionButton;ActionButton::make('Button Label','https://moonshine-laravel.com')
use MoonShine\UI\Components\ActionButton;ActionButton::make('Button Label','https://moonshine-laravel.com')
Открытие в новом окне
Метод blank()
позволяет открыть URL в новом окне. Добавится атрибут target="_blank"
.
ActionButton::make('Button Label', '/')->blank()
ActionButton::make('Button Label', '/')->blank()
Иконка
Метод icon()
позволяет указать иконку для кнопки.
ActionButton::make('Button Label')->icon('pencil')
ActionButton::make('Button Label')->icon('pencil')
Для получения более подробной информации обратитесь к разделу Иконки.
Цвет
Для ActionButton
есть набор методов, которые позволяют установить цвет кнопки:
primary()
, secondary()
, warning()
, success()
и error()
.
ActionButton::make('Button Label')->primary()
ActionButton::make('Button Label')->primary()
Бейдж
Метод badge()
позволяет добавить бейдж к кнопке.
badge(Closure|string|int|float|null $value)
badge(Closure|string|int|float|null $value)
ActionButton::make('Button Label')->badge(fn() => Comment::count())
ActionButton::make('Button Label')->badge(fn() => Comment::count())
onClick
Метод onClick()
позволяет выполнить js-код при клике.
ActionButton::make('Button Label')->onClick(fn() => "alert('Пример')", 'prevent')
ActionButton::make('Button Label')->onClick(fn() => "alert('Пример')", 'prevent')
Если вам необходимо получить данные в методе onClick()
, то воспользуйтесь методом onAfterSet()
.
ActionButton::make('Alert')->onAfterSet(function (?DataWrapperContract $data, ActionButton $button) {return $button->onClick(fn() => 'alert('.$data?->getKey().')');})
ActionButton::make('Alert')->onAfterSet(function (?DataWrapperContract $data, ActionButton $button) {return $button->onClick(fn() => 'alert('.$data?->getKey().')');})
Модальное окно
Основы
Для вызова модального окна при нажатии на кнопку используйте метод inModal()
.
use MoonShine\Contracts\UI\ActionButtonContract;use MoonShine\UI\Components\Modal;/*** @param ?Closure(Modal $modal, ActionButtonContract $ctx): Modal $builder*/inModal(Closure|string|null $title = null,Closure|string|null $content = null,Closure|string|null $name = null,?Closure $builder = null,iterable $components = [],)
use MoonShine\Contracts\UI\ActionButtonContract;use MoonShine\UI\Components\Modal;/*** @param ?Closure(Modal $modal, ActionButtonContract $ctx): Modal $builder*/inModal(Closure|string|null $title = null,Closure|string|null $content = null,Closure|string|null $name = null,?Closure $builder = null,iterable $components = [],)
title
- заголовок модального окна,content
- содержимое модального окна,name
- уникальное наименование модального окна для вызова событий,builder
- замыкание с доступом к компонентуModal
,components
- компоненты.
Параметр content
- это текстовое содержимое Modal. Подходит для отображения простой информации (строк, HTML и т.д.).
Однако, если вы хотите встроить в Modal компоненты (например, поля или формы, реагирующие на изменение значений, реактивность и т.д.),
важно понимать, что MoonShine не сможет "увидеть" такие компоненты, переданные как строка.
Это ограничивает функциональность.
Чтобы MoonShine корректно обрабатывал поля внутри Modal, необходимо передать их в параметре components
.
Если вы строите контент Modal исключительно на компонентах MoonShine (поля, формы и т.д.), используйте параметр components
вместо content
.
Для получения более подробной информации по методам модальных окон, обратитесь к разделу Modal.
use MoonShine\UI\Components\ActionButton;use MoonShine\UI\Components\Modal;ActionButton::make('Button Label')->inModal(title: 'Modal Window Title',content: 'Modal Window Content',name: 'my-modal',builder: fn(Modal $modal, ActionButton $ctx) => $modal)
use MoonShine\UI\Components\ActionButton;use MoonShine\UI\Components\Modal;ActionButton::make('Button Label')->inModal(title: 'Modal Window Title',content: 'Modal Window Content',name: 'my-modal',builder: fn(Modal $modal, ActionButton $ctx) => $modal)
Если вы используете несколько однотипных модальных окон, например в таблицах для каждого элемента, то вам необходимо указывать уникальный name
для каждой.
use MoonShine\Contracts\UI\ActionButtonContract;use MoonShine\UI\Components\ActionButton;ActionButton::make('Button Label')->inModal(name: static fn (mixed $item, ActionButtonContract $ctx): string => "delete-button-{$ctx->getData()?->getKey()}")
use MoonShine\Contracts\UI\ActionButtonContract;use MoonShine\UI\Components\ActionButton;ActionButton::make('Button Label')->inModal(name: static fn (mixed $item, ActionButtonContract $ctx): string => "delete-button-{$ctx->getData()?->getKey()}")
Вы также можете открыть модальное окно с помощью метода toggleModal()
, а если ActionButton
находится внутри модального окна, то просто openModal()
.
use MoonShine\UI\Components\ActionButton;use MoonShine\UI\Components\Modal;Modal::make('Title','Content')->name('my-modal'),ActionButton::make('Open modal window')->toggleModal('my-modal'),
use MoonShine\UI\Components\ActionButton;use MoonShine\UI\Components\Modal;Modal::make('Title','Content')->name('my-modal'),ActionButton::make('Open modal window')->toggleModal('my-modal'),
Асинхронный режим
Если вам нужно загрузить содержимое в модальное окно асинхронно, то включите асинхронный режим с помощью метода async()
у ActionButton
.
ActionButton::make('Button Label',to_page('action_button', fragment: 'doc-content'),)->async()->inModal(title: fn() => 'Modal Window Title',)
ActionButton::make('Button Label',to_page('action_button', fragment: 'doc-content'),)->async()->inModal(title: fn() => 'Modal Window Title',)
О Fragment можно узнать в разделе "Компоненты".
Подтверждение
Метод withConfirm()
позволяет создать кнопку с подтверждением действия.
/*** @param ?Closure(FormBuilderContract $form, mixed $data): FormBuilderContract $formBuilder* @param ?Closure(Modal $modal, ActionButtonContract $ctx): Modal $modalBuilder*/withConfirm(Closure|string|null $title = null,Closure|string|null $content = null,Closure|string|null $button = null,Closure|array|null $fields = null,HttpMethod $method = HttpMethod::POST,?Closure $formBuilder = null,?Closure $modalBuilder = null,Closure|string|null $name = null,)
/*** @param ?Closure(FormBuilderContract $form, mixed $data): FormBuilderContract $formBuilder* @param ?Closure(Modal $modal, ActionButtonContract $ctx): Modal $modalBuilder*/withConfirm(Closure|string|null $title = null,Closure|string|null $content = null,Closure|string|null $button = null,Closure|array|null $fields = null,HttpMethod $method = HttpMethod::POST,?Closure $formBuilder = null,?Closure $modalBuilder = null,Closure|string|null $name = null,)
ActionButton::make('Button Label')->withConfirm(title: 'Confirmation Modal Window Title',content: 'Confirmation Modal Window Content',button: 'Confirmation Modal Window Button',// опционально - дополнительные поля формыfields: null,method: HttpMethod::POST,// опционально - замыкание с FormBuilderformBuilder: null,// опционально - замыкание с ModalmodalBuilder: null,name: 'my-modal',)
ActionButton::make('Button Label')->withConfirm(title: 'Confirmation Modal Window Title',content: 'Confirmation Modal Window Content',button: 'Confirmation Modal Window Button',// опционально - дополнительные поля формыfields: null,method: HttpMethod::POST,// опционально - замыкание с FormBuilderformBuilder: null,// опционально - замыкание с ModalmodalBuilder: null,name: 'my-modal',)
Если вы используете несколько однотипных модальных окон, например в таблицах для каждого элемента, то вам необходимо указывать уникальный name
для каждой.
ActionButton::make('Button Label')->inModal(name: static fn (mixed $item, ActionButtonContract $ctx): string => "delete-button-{$ctx->getData()?->getKey()}")
ActionButton::make('Button Label')->inModal(name: static fn (mixed $item, ActionButtonContract $ctx): string => "delete-button-{$ctx->getData()?->getKey()}")
Offcanvas
Для того чтобы при нажатии на кнопку вызывалась боковая панель (Offcanvas), используйте метод inOffCanvas()
.
use MoonShine\UI\Components\ActionButton;use MoonShine\UI\Components\OffCanvas;ActionButton::make('Button Label')->inOffCanvas(title: fn() => 'Offcanvas Title',content: fn() => 'Content',name: false,builder: fn(OffCanvas $offCanvas, ActionButton $ctx) => $offCanvas->left(),// опционально - необходимо чтобы компоненты были доступны для поиска в системе, т.к. content всего лишь HTMLcomponents: [],)
use MoonShine\UI\Components\ActionButton;use MoonShine\UI\Components\OffCanvas;ActionButton::make('Button Label')->inOffCanvas(title: fn() => 'Offcanvas Title',content: fn() => 'Content',name: false,builder: fn(OffCanvas $offCanvas, ActionButton $ctx) => $offCanvas->left(),// опционально - необходимо чтобы компоненты были доступны для поиска в системе, т.к. content всего лишь HTMLcomponents: [],)
Группировка
Если вам необходимо организовать логику с несколькими ActionButton
, при этом некоторые из них должны быть скрыты или отображены в выпадающем меню, используйте компонент ActionGroup
.
use MoonShine\UI\Components\ActionButton;use MoonShine\UI\Components\ActionGroup;ActionGroup::make([ActionButton::make('Button 1', '/')->canSee(fn() => false),ActionButton::make('Button 2', '/', $model)->canSee(fn($model) => $model->active)])
use MoonShine\UI\Components\ActionButton;use MoonShine\UI\Components\ActionGroup;ActionGroup::make([ActionButton::make('Button 1', '/')->canSee(fn() => false),ActionButton::make('Button 2', '/', $model)->canSee(fn($model) => $model->active)])
Подробнее о компоненте ActionGroup.
Отображение
Благодаря ActionGroup
вы также можете изменить отображение кнопок, отображать их в линию или в выпадающем меню для экономии места.
use MoonShine\UI\Components\ActionButton;use MoonShine\UI\Components\ActionGroup;ActionGroup::make([ActionButton::make('Button 1', '/')->showInLine(),ActionButton::make('Button 2', '/')->showInDropdown()])
use MoonShine\UI\Components\ActionButton;use MoonShine\UI\Components\ActionGroup;ActionGroup::make([ActionButton::make('Button 1', '/')->showInLine(),ActionButton::make('Button 2', '/')->showInDropdown()])
Массовые действия
Метод bulk()
позволяет создать кнопку массового действия для ModelResource
.
protected function indexButtons(): ListOf{return parent::indexButtons()->add(ActionButton::make('Link', '/endpoint')->bulk());}
protected function indexButtons(): ListOf{return parent::indexButtons()->add(ActionButton::make('Link', '/endpoint')->bulk());}
Метод bulk()
, используется только внутри ModelResource
.
Асинхронный режим
Метод async()
позволяет реализовать асинхронную работу для ActionButton
.
use MoonShine\Support\DTOs\AsyncCallback;use MoonShine\Support\Enums\HttpMethod;async(HttpMethod $method = HttpMethod::GET,?string $selector = null,array $events = [],?AsyncCallback $callback = null,)
use MoonShine\Support\DTOs\AsyncCallback;use MoonShine\Support\Enums\HttpMethod;async(HttpMethod $method = HttpMethod::GET,?string $selector = null,array $events = [],?AsyncCallback $callback = null,)
$method
- метод асинхронного запроса,$selector
- селектор элемента, содержимое которого изменится в соответствии с ответом,$events
- события, которые будут вызваны после успешного запроса,$callback
- js функция обратного вызова после получения ответа.
ActionButton::make('Button Label', '/endpoint')->async()
ActionButton::make('Button Label', '/endpoint')->async()
Уведомления
Если вам нужно отобразить уведомление или сделать редирект после клика, то достаточно реализовать json ответ согласно следующей структуре:
{"message": "Toast","messageType": "success","redirect": "/url"}
{"message": "Toast","messageType": "success","redirect": "/url"}
Параметр redirect
является необязательным.
HTML содержимое
Если вам нужно заменить область HTML по клику, то можно вернуть HTML содержимое или json с ключом html в ответе, например:
{"html": "Html content"}
{"html": "Html content"}
ActionButton::make('Button Label', '/endpoint')->async(selector: '#my-selector')
ActionButton::make('Button Label', '/endpoint')->async(selector: '#my-selector')
События
После успешного запроса вы можете вызвать события.
ActionButton::make('Button Label', '/endpoint')->async(events: [AlpineJs::event(JsEvent::TABLE_UPDATED, $this->getListComponentName())])
ActionButton::make('Button Label', '/endpoint')->async(events: [AlpineJs::event(JsEvent::TABLE_UPDATED, $this->getListComponentName())])
Для работы события JsEvent::TABLE_UPDATED
у таблицы должен быть включен асинхронный режим.
Обратный вызов
Если вам нужно обработать ответ иным способом, необходимо реализовать функцию-обработчик и указать её в методе async()
.
ActionButton::make('Button Label', '/endpoint')->async(callback: AsyncCallback::with(responseHandler: 'myFunction'))
ActionButton::make('Button Label', '/endpoint')->async(callback: AsyncCallback::with(responseHandler: 'myFunction'))
document.addEventListener("moonshine:init", () => {MoonShine.onCallback('myFunction', function(response, element, events, component) {if(response.confirmed === true) {component.$dispatch('toast', {type: 'success', text: 'Success'})} else {component.$dispatch('toast', {type: 'error', text: 'Error'})}})})
document.addEventListener("moonshine:init", () => {MoonShine.onCallback('myFunction', function(response, element, events, component) {if(response.confirmed === true) {component.$dispatch('toast', {type: 'success', text: 'Success'})} else {component.$dispatch('toast', {type: 'error', text: 'Error'})}})})
Подробности в разделе Js.
Вызов методов
method()
позволяет указать имя метода в ресурсе и вызвать его асинхронно при нажатии на ActionButton
без необходимости создания дополнительных контроллеров.
method(string $method,array|Closure $params = [],?string $message = null,?string $selector = null,array $events = [],?AsyncCallback $callback = null,?PageContract $page = null,?ResourceContract $resource = null,)
method(string $method,array|Closure $params = [],?string $message = null,?string $selector = null,array $events = [],?AsyncCallback $callback = null,?PageContract $page = null,?ResourceContract $resource = null,)
$method
- имя метода,$params
- опционально - параметры для запроса,$message
- опционально - сообщение при успешном выполнении,$selector
- опционально - селектор элемента, содержимое которого изменится,$events
- опционально - события, которые будут вызваны после успешного запроса,$callback
- опционально - js функция обратного вызова после получения ответа,$page
- опционально - страница, содержащая метод (если кнопка находится вне страницы и ресурса),$resource
- опционально - ресурс, содержащий метод (если кнопка находится вне ресурса).
ActionButton::make('Button Label')->method('updateSomething')
ActionButton::make('Button Label')->method('updateSomething')
Если метод возвращает файл для скачивания, вам необходимо добавить метод download()
.
ActionButton::make('ZIP')->method('zip')->download()
ActionButton::make('ZIP')->method('zip')->download()
Примеры методов:
// С уведомлениемpublic function updateSomething(MoonShineRequest $request): MoonShineJsonResponse{// $request->getResource();// $request->getResource()->getItem();// $request->getPage();return MoonShineJsonResponse::make()->toast('My message', ToastType::SUCCESS);}// Редиректpublic function updateSomething(MoonShineRequest $request): MoonShineJsonResponse{return MoonShineJsonResponse::make()->redirect('/');}// Редиректpublic function updateSomething(MoonShineRequest $request): RedirectResponse{return back();}// Исключениеpublic function updateSomething(MoonShineRequest $request): void{throw new \Exception('My message');}// Пользовательский JSON-ответpublic function updateSomething(MoonShineRequest $request){return MoonShineJsonResponse::make()->html('Content');}
// С уведомлениемpublic function updateSomething(MoonShineRequest $request): MoonShineJsonResponse{// $request->getResource();// $request->getResource()->getItem();// $request->getPage();return MoonShineJsonResponse::make()->toast('My message', ToastType::SUCCESS);}// Редиректpublic function updateSomething(MoonShineRequest $request): MoonShineJsonResponse{return MoonShineJsonResponse::make()->redirect('/');}// Редиректpublic function updateSomething(MoonShineRequest $request): RedirectResponse{return back();}// Исключениеpublic function updateSomething(MoonShineRequest $request): void{throw new \Exception('My message');}// Пользовательский JSON-ответpublic function updateSomething(MoonShineRequest $request){return MoonShineJsonResponse::make()->html('Content');}
Методы, вызываемые через ActionButton
в ресурсе, должны быть публичными!
Для доступа к данным из запроса вы должны передать их в параметрах.
Передача текущего элемента
Если в запросе присутствует resourceItem
, вы можете получить доступ к текущему элементу в ресурсе через метод getItem()
.
Когда в данных есть модель, и кнопка создается в методе indexButtons()
или detailButtons()
или formButtons()
TableBuilder, CardsBuilder или FormBuilder,
она автоматически заполняется данными, и параметры будут содержать resourceItem
.
Когда кнопка находится на странице формы ModelResource
, вы можете передать id текущего элемента.
ActionButton::make('Button Label')->method('updateSomething',params: ['resourceItem' => $this->getResource()->getItemID()])
ActionButton::make('Button Label')->method('updateSomething',params: ['resourceItem' => $this->getResource()->getItemID()])
Когда кнопка находится в индексной таблице ModelResource
, нужно использовать замыкание.
ActionButton::make('Button Label')->method('updateSomething',params: fn(Model $item) => ['resourceItem' => $item->getKey()])
ActionButton::make('Button Label')->method('updateSomething',params: fn(Model $item) => ['resourceItem' => $item->getKey()])
Значения полей
Метод withSelectorsParams()
позволяет передавать значения полей с запросом, используя селекторы элементов.
ActionButton::make('Button Label')->method('updateSomething')->withSelectorsParams(['alias' => '[data-column="title"]','slug' => '#slug',])
ActionButton::make('Button Label')->method('updateSomething')->withSelectorsParams(['alias' => '[data-column="title"]','slug' => '#slug',])
use MoonShine\Laravel\Http\Responses\MoonShineJsonResponse;use MoonShine\Laravel\MoonShineRequest;public function updateSomething(MoonShineRequest $request): MoonShineJsonResponse{return MoonShineJsonResponse::make()->toast($request->get('slug', 'Error'));}
use MoonShine\Laravel\Http\Responses\MoonShineJsonResponse;use MoonShine\Laravel\MoonShineRequest;public function updateSomething(MoonShineRequest $request): MoonShineJsonResponse{return MoonShineJsonResponse::make()->toast($request->get('slug', 'Error'));}
При использовании метода withSelectorsParams()
запросы будут отправляться через POST
.
Скачивание
Вызываемый метод может возвращать BinaryFileResponse
, что позволяет скачать файл.
ActionButton::make('Download')->method('download')
ActionButton::make('Download')->method('download')
use Symfony\Component\HttpFoundation\BinaryFileResponse;public function download(): BinaryFileResponse{// ...return response()->download($file);}
use Symfony\Component\HttpFoundation\BinaryFileResponse;public function download(): BinaryFileResponse{// ...return response()->download($file);}
Отправка событий
Для отправки javascript-событий вы можете использовать метод dispatchEvent()
.
dispatchEvent(array|string $events)
dispatchEvent(array|string $events)
ActionButton::make('Refresh')->dispatchEvent(AlpineJs::event(JsEvent::TABLE_UPDATED, 'index-table'))
ActionButton::make('Refresh')->dispatchEvent(AlpineJs::event(JsEvent::TABLE_UPDATED, 'index-table'))
По умолчанию при вызове события с запросом будут отправлены все query параметры (например, ?param=value
) из url
(указанного при создании ActionButton
).
Исключить ненужные можно через параметр exclude
.
ActionButton::make('Refresh')->dispatchEvent(AlpineJs::event(JsEvent::TABLE_UPDATED, 'index-table'),exclude: ['something'],)
ActionButton::make('Refresh')->dispatchEvent(AlpineJs::event(JsEvent::TABLE_UPDATED, 'index-table'),exclude: ['something'],)
Также можно полностью исключить отправку withoutPayload
.
ActionButton::make('Refresh')->dispatchEvent(AlpineJs::event(JsEvent::TABLE_UPDATED, 'index-table'),withoutPayload: true)
ActionButton::make('Refresh')->dispatchEvent(AlpineJs::event(JsEvent::TABLE_UPDATED, 'index-table'),withoutPayload: true)
Параметры запроса URL
Вы можете включить параметры текущего запроса URL (например, ?param=value
) в запрос.
ActionButton::make('Button Label')->withQueryParams()
ActionButton::make('Button Label')->withQueryParams()
Наполнение данными
При работе с ModelResource
, кнопки действий ActionButton
обычно автоматически наполняются необходимыми данными.
Этот процесс происходит "под капотом" с использованием метода setData()
.
Давайте рассмотрим этот механизм подробнее.
ActionButton::make('Button Label')->setData(?DataWrapperContract $data = null)
ActionButton::make('Button Label')->setData(?DataWrapperContract $data = null)
Подробнее о DataWrapperContract
читайте в разделе TypeCasts.
Также доступны методы с колбеками до и после наполнения кнопки.
ActionButton::make('Button Label')->onBeforeSet(fn(?DataWrapperContract $data, ActionButton $ctx) => $data)
ActionButton::make('Button Label')->onBeforeSet(fn(?DataWrapperContract $data, ActionButton $ctx) => $data)
ActionButton::make('Button Label')->onAfterSet(function(?DataWrapperContract $data, ActionButton $ctx): void {// logic})
ActionButton::make('Button Label')->onAfterSet(function(?DataWrapperContract $data, ActionButton $ctx): void {// logic})