- Описание
- Создание поля
- Отображение поля
- Атрибуты
- Модифицирование значения поля
- Редактирование в режиме preview
- Ассеты
- Трейт Macroable
- Реактивность
- Динамическое отображение
- Кастомное поле
Описание
Все поля наследуют базовый класс Field
, который предоставляет базовые методы работы с полями.
Создание поля
Для создания экземпляра поля используется статический метод make()
.
make(Closure|string|null $label = null,?string $column = null,?Closure $formatted = null)
make(Closure|string|null $label = null,?string $column = null,?Closure $formatted = null)
$label
- заголовок поля,$column
- связь столбца в базе и атрибутаname
у поля ввода (например:description
><input name="description">
). Если это поле отношения, то используется название отношения (например: countries),$formatted
- замыкание для форматирования значения поля в режиме preview (дляBelongsTo
иBelongsToMany
форматирует значения для выбора).
В $label
можно добавлять html теги, они не будут экранироваться.
Если не указать $column
, то поле в базе данных будет определено автоматически на основе $label
(только для английского языка).
Пример замыкания $formatted
для форматирования значения:
use MoonShine\UI\Fields\Text;Text::make('Name','first_name',fn($item) => $item->first_name . ' ' . $item->last_name)
use MoonShine\UI\Fields\Text;Text::make('Name','first_name',fn($item) => $item->first_name . ' ' . $item->last_name)
Поля не поддерживающие $formatted
: Json
, File
, Range
, RangeSlider
, DateRange
, Select
, Enum
, HasOne
, HasMany
.
Отображение поля
Label
Если необходимо изменить label после создания экземпляра поля, можно воспользоваться методом setLabel()
.
setLabel(Closure|string $label)
setLabel(Closure|string $label)
use MoonShine\UI\Fields\Field;use MoonShine\UI\Fields\Slug;Slug::make('Slug')->setLabel(fn(Field $field) => $field->getData()?->exists? 'Slug (do not change)': 'Slug')
use MoonShine\UI\Fields\Field;use MoonShine\UI\Fields\Slug;Slug::make('Slug')->setLabel(fn(Field $field) => $field->getData()?->exists? 'Slug (do not change)': 'Slug')
Для перевода label необходимо в качестве названия передать ключ перевода и добавить метод translatable()
.
translatable(string $key = '')
translatable(string $key = '')
Text::make('ui.Title')->translatable()Text::make('Title')->translatable('ui')
Text::make('ui.Title')->translatable()Text::make('Title')->translatable('ui')
Text::make(fn() => __('Title'))
Text::make(fn() => __('Title'))
insideLabel()
Для оборачивания поля в тег <label>
можно использовать метод insideLabel()
.
Text::make('Name')->insideLabel()
Text::make('Name')->insideLabel()
beforeLabel()
Для отображения label после поля ввода можно использовать метод beforeLabel()
.
Text::make('Name')->beforeLabel()
Text::make('Name')->beforeLabel()
Подсказка
Подсказка с описанием можно создать с помощью метода hint()
.
hint(string $hint)
hint(string $hint)
Number::make('Rating')->hint('From 0 to 5')->min(0)->max(5)->stars()
Number::make('Rating')->hint('From 0 to 5')->min(0)->max(5)->stars()
Ссылка
Полю можно добавить ссылку (например с инструкциями) link()
.
link(string|Closure $link,string|Closure $name = '',?string $icon = null,bool $withoutIcon = false,bool $blank = false)
link(string|Closure $link,string|Closure $name = '',?string $icon = null,bool $withoutIcon = false,bool $blank = false)
Text::make('Link')->link('https://cutcode.dev', 'CutCode', blank: true)
Text::make('Link')->link('https://cutcode.dev', 'CutCode', blank: true)
Badge
Для отображения поля в режиме preview в виде badge, необходимо воспользоваться методом badge()
.
badge(string|Color|Closure|null $color = null)
badge(string|Color|Closure|null $color = null)
Доступные цвета:
primary secondary success warning error info purple pink blue green yellow red gray
use MoonShine\Support\Enums\Color;Text::make('Title')->badge(Color::PRIMARY)
use MoonShine\Support\Enums\Color;Text::make('Title')->badge(Color::PRIMARY)
use MoonShine\UI\Fields\Field;Text::make('Title')->badge(fn($status, Field $field) => 'green')
use MoonShine\UI\Fields\Field;Text::make('Title')->badge(fn($status, Field $field) => 'green')
Горизонтально отображение
Метод horizontal()
позволяет отображать название и поле горизонтально.
horizontal()
horizontal()
Text::make('Title')->horizontal()
Text::make('Title')->horizontal()
Обертка
Поля при отображении в формах используют специальную обертку для заголовков, подсказок, ссылок и тд.
Иногда может возникнуть ситуация, когда требуется отобразить поле без дополнительных элементов.
Метод withoutWrapper()
позволяет отключить создание обёртки.
withoutWrapper(mixed $condition = null)
withoutWrapper(mixed $condition = null)
Text::make('Title')->withoutWrapper()
Text::make('Title')->withoutWrapper()
Text wrap
Если поля в режиме предварительного просмотра не помещаются в область, выделенную им по ширине, они выходят за ее пределы.
Но этим поведением можно управлять с помощью метода textWrap()
, определяющего, как именно обрезать текст.
Clamp:
Text::make('Field')->textWrap(TextWrap::CLAMP)
Text::make('Field')->textWrap(TextWrap::CLAMP)
Ellipsis:
Text::make('Field')->textWrap(TextWrap::ELLIPSIS)
Text::make('Field')->textWrap(TextWrap::ELLIPSIS)
Disable:
Text::make('Field')->withoutTextWrap()
Text::make('Field')->withoutTextWrap()
По умолчанию поле Text
имеет Elipsis, а Textarea
имеет Clamp.
Сортировка
Для возможности сортировки поля в таблицах (на главной странице) необходимо добавить метод sortable()
.
sortable(Closure|string|null $callback = null)
sortable(Closure|string|null $callback = null)
Text::make('Title')->sortable()
Text::make('Title')->sortable()
Метод sortable()
в качестве параметра может принимать название поля в базе данных или замыкание.
use Illuminate\Contracts\Database\Eloquent\Builder;use MoonShine\Laravel\Fields\Relationships\BelongsTo;use MoonShine\UI\Fields\Text;BelongsTo::make('Author')->sortable('author_id'),Text::make('Title')->sortable(function (Builder $query, string $column, string $direction) {$query->orderBy($column, $direction);})
use Illuminate\Contracts\Database\Eloquent\Builder;use MoonShine\Laravel\Fields\Relationships\BelongsTo;use MoonShine\UI\Fields\Text;BelongsTo::make('Author')->sortable('author_id'),Text::make('Title')->sortable(function (Builder $query, string $column, string $direction) {$query->orderBy($column, $direction);})
Режимы отображения
Подробнее о режимах отображения поля можно прочитать в разделе Основы > Смена режима отображения.
Режим "Default"
Чтобы поле вне зависимости от контекста всегда работало в режиме "Default" (отображение "input" поля), необходимо использовать метод defaultMode()
.
Text::make('Title')->defaultMode()
Text::make('Title')->defaultMode()
Режим "Preview"
Чтобы поле вне зависимости от контекста всегда работало в режиме "Preview", необходимо использовать метод previewMode()
.
Text::make('Title')->previewMode()
Text::make('Title')->previewMode()
Режим "RawMode"
Чтобы поле вне зависимости от контекста всегда работало в режиме "RawMode" (отображение исходного состояния), необходимо использовать метод rawMode()
.
Text::make('Title')->rawMode()
Text::make('Title')->rawMode()
Атрибуты
Основные html атрибуты, такие как required
, disabled
и readonly
, у поля необходимо задавать через соответствующие методы.
Required
required(Closure|bool|null $condition = null)
required(Closure|bool|null $condition = null)
Text::make('Title')->required()
Text::make('Title')->required()
Disabled
disabled(Closure|bool|null $condition = null)
disabled(Closure|bool|null $condition = null)
Text::make('Title')->disabled()
Text::make('Title')->disabled()
Readonly
readonly(Closure|bool|null $condition = null)
readonly(Closure|bool|null $condition = null)
Text::make('Title')->readonly()
Text::make('Title')->readonly()
Другие атрибуты
Чтобы указать любые другие атрибуты, используется метод customAttributes()
.
Поля являются компонентами, подробнее об атрибутах читайте в разделе Атрибуты компонентов.
customAttributes(array $attributes,bool $override = false)
customAttributes(array $attributes,bool $override = false)
$attributes
- массив атрибутов,$override
- для добавления атрибутов к полю, используетсяmerge
. Если атрибут, который вы хотите добавить к полю, уже присутствует, то он добавлен не будет.$override = true
позволяет изменить данное поведение и перезаписать уже добавленный атрибут.
Password::make('Title')->customAttributes(['autocomplete' => 'off'])
Password::make('Title')->customAttributes(['autocomplete' => 'off'])
Атрибуты для wrapper поля
Метод customWrapperAttributes()
позволяет добавить атрибуты для обертки поля.
customWrapperAttributes(array $attributes)
customWrapperAttributes(array $attributes)
Password::make('Title')->customWrapperAttributes(['class' => 'mt-8'])
Password::make('Title')->customWrapperAttributes(['class' => 'mt-8'])
Модифицирование атрибута "name"
Так как атрибут name
генерируется на основе вложенности и имеет сложную логику формирования, то для его изменения требуется воспользоваться методом setNameAttribute()
.
Text::make('Name')->setNameAttribute('custom_name')
Text::make('Name')->setNameAttribute('custom_name')
wrapName
Для того чтобы добавить wrapper для значения атрибута name
, используется метод wrapName()
.
Text::make('Name')->wrapName('options')
Text::make('Name')->wrapName('options')
В результате атрибут name примет вид <input name="options[name]>
. Это особенно полезно для настройки фильтров.
virtualName
Иногда необходимо хранить по одному полю ввода два значения Field. Например, по условию отображение одно из полей может становиться невидимым, но присутствовать в DOM и отправляться вместе с запросом.
// это поле отображается в DOM на одном условииFile::make('image')// это поле отображается в DOM на другом условииFile::make('image')
// это поле отображается в DOM на одном условииFile::make('image')// это поле отображается в DOM на другом условииFile::make('image')
Для того чтобы изменить атрибут name у этих полей, используется метод virtualName()
.
File::make('image')->virtualColumn('image_1')// ...File::make('image')->virtualColumn('image_2')
File::make('image')->virtualColumn('image_1')// ...File::make('image')->virtualColumn('image_2')
Далее, например в onApply()
методе, мы обрабатываем эти поля по своему усмотрению.
Модифицирование значения поля
Значение по умолчанию
Для указания значения по умолчанию используется метод default()
.
default(mixed $default)
default(mixed $default)
Text::make('Name')->default('Default value')
Text::make('Name')->default('Default value')
Enum::make('Status')->attach(ColorEnum::class)->default(ColorEnum::from('B')->value)
Enum::make('Status')->attach(ColorEnum::class)->default(ColorEnum::from('B')->value)
Nullable
Если необходимо у поля по умолчанию сохранять NULL, то необходимо использовать метод nullable()
.
nullable(Closure|bool|null $condition = null)
nullable(Closure|bool|null $condition = null)
Password::make('Title')->nullable()
Password::make('Title')->nullable()
Изменение отображения
Когда необходимо изменить view с помощью fluent interface можно воспользоваться методом customView()
.
customView(string $view, array $data = [])
customView(string $view, array $data = [])
Text::make('Title')->customView('fields.my-custom-input')
Text::make('Title')->customView('fields.my-custom-input')
Метод changePreview()
позволяет переопределить view для превью (везде кроме формы).
use MoonShine\UI\Components\Thumbnails;use MoonShine\UI\Fields\Text;Text::make('Thumbnail')->changePreview(function (?string $value, Text $field) {return Thumbnails::make($value);})
use MoonShine\UI\Components\Thumbnails;use MoonShine\UI\Fields\Text;Text::make('Thumbnail')->changePreview(function (?string $value, Text $field) {return Thumbnails::make($value);})
Хук до рендера
Если вам необходимо получить доступ к полю непосредственно перед рендером, для этого можно воспользоваться методом onBeforeRender()
.
/*** @param Closure(static $ctx): void $onBeforeRender*/onBeforeRender(Closure $onBeforeRender)
/*** @param Closure(static $ctx): void $onBeforeRender*/onBeforeRender(Closure $onBeforeRender)
Text::make('Thumbnail')->onBeforeRender(function(Text $ctx) {// ...})
Text::make('Thumbnail')->onBeforeRender(function(Text $ctx) {// ...})
Получение значения из запроса
Метод onRequestValue()
позволяет переопределить логику получения значения из Request.
/*** @param Closure(mixed $value, string $name, mixed $default, static $ctx): mixed $callback*/onRequestValue(Closure $callback)
/*** @param Closure(mixed $value, string $name, mixed $default, static $ctx): mixed $callback*/onRequestValue(Closure $callback)
$value
- значение полученное по умолчанию,$name
- наименование параметра запроса,$default
- значение поля по умолчанию, при отсутствии в запросе,$ctx
- текущее поле,
Статический метод requestValueResolver()
позволяет глобально переопределить логику получения значения из Request для всех полей.
/*** @param Closure(string|int|null $index, mixed $default, static $ctx): mixed $resolver*/requestValueResolver(Closure $resolver)
/*** @param Closure(string|int|null $index, mixed $default, static $ctx): mixed $resolver*/requestValueResolver(Closure $resolver)
FormElement::requestValueResolver(function (string|int|null $index, mixed $default, static $ctx): mixed {return request()->input($ctx->getRequestNameDot($index), $default);})
FormElement::requestValueResolver(function (string|int|null $index, mixed $default, static $ctx): mixed {return request()->input($ctx->getRequestNameDot($index), $default);})
До и после рендеринга
Методы beforeRender()
и afterRender()
позволяют вывести какую-то информацию перед и после поля соответственно.
beforeRender(Closure $closure)afterRender(Closure $closure)
beforeRender(Closure $closure)afterRender(Closure $closure)
use MoonShine\UI\Fields\Field;Text::make('Title')->beforeRender(function(Field $field) {return $field->preview();})
use MoonShine\UI\Fields\Field;Text::make('Title')->beforeRender(function(Field $field) {return $field->preview();})
Условные методы
Отображать компонент можно по условию, воспользовавшись методом canSee()
.
Text::make('Name')->canSee(function (Text $field) {return $field->toValue() !== 'hide';})
Text::make('Name')->canSee(function (Text $field) {return $field->toValue() !== 'hide';})
use MoonShine\Laravel\Fields\Relationships\BelongsTo;// или для полей отношенийBelongsTo::make('Item', 'item', resource: ItemResource::class)->canSee(function (Comment $comment, BelongsTo $field) {// ваше условие})
use MoonShine\Laravel\Fields\Relationships\BelongsTo;// или для полей отношенийBelongsTo::make('Item', 'item', resource: ItemResource::class)->canSee(function (Comment $comment, BelongsTo $field) {// ваше условие})
Метод when()
реализует fluent interface и выполнит callback, когда первый аргумент, переданный методу, имеет значение true.
when($value = null,?callable $callback = null,?callable $default = null)
when($value = null,?callable $callback = null,?callable $default = null)
use MoonShine\UI\Fields\Field;Text::make('Slug')->when(fn() => true,fn(Field $field) => $field->locked())
use MoonShine\UI\Fields\Field;Text::make('Slug')->when(fn() => true,fn(Field $field) => $field->locked())
Метод unless()
обратный методу when()
.
unless($value = null,?callable $callback = null,?callable $default = null)
unless($value = null,?callable $callback = null,?callable $default = null)
Apply
У каждого поля реализован метод apply()
, который трансформирует данные.
Чтобы переопределить стандартный apply
у поля, можно воспользоваться методом onApply()
.
Подробнее о цикле жизни применения поля можно прочитать в разделе Основы > Процесс применения полей.
/*** @param Closure(mixed, mixed, FieldContract): mixed $onApply*/onApply(Closure $onApply)
/*** @param Closure(mixed, mixed, FieldContract): mixed $onApply*/onApply(Closure $onApply)
use Illuminate\Database\Eloquent\Model;use Illuminate\Support\Facades\Storage;use MoonShine\UI\Fields\Text;Text::make('Thumbnail by link', 'thumbnail')->onApply(function(Model $item, $value, Field $field) {$path = 'thumbnail.jpg';if ($value) {$item->thumbnail = Storage::put($path, file_get_contents($value));}return $item;})
use Illuminate\Database\Eloquent\Model;use Illuminate\Support\Facades\Storage;use MoonShine\UI\Fields\Text;Text::make('Thumbnail by link', 'thumbnail')->onApply(function(Model $item, $value, Field $field) {$path = 'thumbnail.jpg';if ($value) {$item->thumbnail = Storage::put($path, file_get_contents($value));}return $item;})
Пример onApply
для фильтров:
use MoonShine\UI\Fields\Text;use Illuminate\Contracts\Database\Eloquent\Builder;Text::make('Title')->onApply(function (Builder $query, mixed $value, Text $field) {$query->where('title', $value);})
use MoonShine\UI\Fields\Text;use Illuminate\Contracts\Database\Eloquent\Builder;Text::make('Title')->onApply(function (Builder $query, mixed $value, Text $field) {$query->where('title', $value);})
Для того чтобы выполнить какие-либо действия до "apply", можно воспользоваться методом onBeforeApply()
.
/*** @param Closure(mixed, mixed, FieldContract): static $onBeforeApply*/onBeforeApply(Closure $onBeforeApply)
/*** @param Closure(mixed, mixed, FieldContract): static $onBeforeApply*/onBeforeApply(Closure $onBeforeApply)
Для того чтобы выполнить какие-либо действия после "apply", можно воспользоваться методом onAfterApply()
.
/*** @param Closure(mixed, mixed, FieldContract): static $onBeforeApply*/onAfterApply(Closure $onBeforeApply)
/*** @param Closure(mixed, mixed, FieldContract): static $onBeforeApply*/onAfterApply(Closure $onBeforeApply)
Выполнять метод apply()
можно по условию, воспользовавшись методом canApply()
.
canApply(Closure $canApply)
canApply(Closure $canApply)
Text::make('Title')->canApply(fn() => false)
Text::make('Title')->canApply(fn() => false)
Метод refreshAfterApply()
инициирует ререндер поля после "применения".
Так же можно влиять на этот процесс через колбэк.
refreshAfterApply(?Closure $callback = null)
refreshAfterApply(?Closure $callback = null)
Text::make('Title')->refreshAfterApply(fn(Text $ctx) => $ctx)
Text::make('Title')->refreshAfterApply(fn(Text $ctx) => $ctx)
У полей File
эта функция включена по умолчанию для обновления "preview".
Это поведение можно отключить с помощью метода disableRefreshAfterApply()
или переопределить в соответствии со своей логикой.
Image::make('Avatar')->disableRefreshAfterApply()
Image::make('Avatar')->disableRefreshAfterApply()
Image::make('Avatar')->refreshAfterApply(fn(Image $ctx) => $ctx)
Image::make('Avatar')->refreshAfterApply(fn(Image $ctx) => $ctx)
Глобальное определение apply логики
Если вы хотите глобально для определенного поля изменить логику apply
, то вы можете создать apply
класс и привязать его к необходимому полю.
Для начала создайте apply
класс:
php artisan moonshine:apply FileModelApply
php artisan moonshine:apply FileModelApply
О всех поддерживаемых опциях можно узнать в разделе Команды.
use MoonShine\Contracts\UI\ApplyContract;use MoonShine\Contracts\UI\FieldContract;/*** @implements ApplyContract<File>*/final class FileModelApply implements ApplyContract{/*** @param File $field*/public function apply(FieldContract $field): Closure{return function (mixed $item) use ($field): mixed {$requestValue = $field->getRequestValue();$newValue = // ...return data_set($item, $field->getColumn(), $newValue);};}}
use MoonShine\Contracts\UI\ApplyContract;use MoonShine\Contracts\UI\FieldContract;/*** @implements ApplyContract<File>*/final class FileModelApply implements ApplyContract{/*** @param File $field*/public function apply(FieldContract $field): Closure{return function (mixed $item) use ($field): mixed {$requestValue = $field->getRequestValue();$newValue = // ...return data_set($item, $field->getColumn(), $newValue);};}}
Далее зарегистрируйте его для поля:
use Illuminate\Support\ServiceProvider;use MoonShine\Contracts\Core\DependencyInjection\CoreContract;use MoonShine\Laravel\DependencyInjection\MoonShine;use MoonShine\Laravel\DependencyInjection\MoonShineConfigurator;use MoonShine\Laravel\DependencyInjection\ConfiguratorContract;use MoonShine\Contracts\Core\DependencyInjection\AppliesRegisterContract;use MoonShine\UI\Applies\AppliesRegister;use App\MoonShine\Applies\FileModelApply;use MoonShine\UI\Fields\File;use MoonShine\Laravel\Resources\ModelResource;class MoonShineServiceProvider extends ServiceProvider{/*** @param MoonShine $core* @param MoonShineConfigurator $config* @param AppliesRegister $applies**/public function boot(CoreContract $core,ConfiguratorContract $config,AppliesRegisterContract $applies,): void{$applies// resource group, default ModelResource->for(ModelResource::class)// type fields or filters->fields()->add(File::class, FileModelApply::class);}}
use Illuminate\Support\ServiceProvider;use MoonShine\Contracts\Core\DependencyInjection\CoreContract;use MoonShine\Laravel\DependencyInjection\MoonShine;use MoonShine\Laravel\DependencyInjection\MoonShineConfigurator;use MoonShine\Laravel\DependencyInjection\ConfiguratorContract;use MoonShine\Contracts\Core\DependencyInjection\AppliesRegisterContract;use MoonShine\UI\Applies\AppliesRegister;use App\MoonShine\Applies\FileModelApply;use MoonShine\UI\Fields\File;use MoonShine\Laravel\Resources\ModelResource;class MoonShineServiceProvider extends ServiceProvider{/*** @param MoonShine $core* @param MoonShineConfigurator $config* @param AppliesRegister $applies**/public function boot(CoreContract $core,ConfiguratorContract $config,AppliesRegisterContract $applies,): void{$applies// resource group, default ModelResource->for(ModelResource::class)// type fields or filters->fields()->add(File::class, FileModelApply::class);}}
Заполнение
Поля можно заполнить значениями, используя метод fill()
.
Более подробно о процессе заполнения поля можно прочитать в разделе Основы > Изменить наполнение.
fill(mixed $value = null,?DataWrapperContract $casted = null,int $index = 0)
fill(mixed $value = null,?DataWrapperContract $casted = null,int $index = 0)
Text::make('Title')->fill('Some title')
Text::make('Title')->fill('Some title')
Изменение логики наполнения поля
Для того чтобы изменить логику заполнения поля, можно использовать метод changeFill()
.
Select::make('Images')->options(['/images/1.png' => 'Picture 1','/images/2.png' => 'Picture 2',])->multiple()->changeFill(fn(Article $article, Select $ctx) => $article->images->map(fn($value) => "https://cutcode.dev$value")->toArray());
Select::make('Images')->options(['/images/1.png' => 'Picture 1','/images/2.png' => 'Picture 2',])->multiple()->changeFill(fn(Article $article, Select $ctx) => $article->images->map(fn($value) => "https://cutcode.dev$value")->toArray());
В данном примере к путям изображений будет добавлено https://cutcode.dev
.
Действия после наполнения поля
Для применения логики к уже наполненному полю можно использовать метод afterFill()
.
Похожий по логике метод when срабатывает в момент создания экземпляра поля, когда оно еще не наполнено.
Метод afterFill()
работает уже с наполненным полем.
Select::make('Links')->options(['/images/1.png' => 'Picture 1','/images/2.png' => 'Picture 2',])->multiple()->afterFill(function(Select $ctx) {if(collect($ctx->toValue())->every(fn($value) => str_contains($value, 'cutcode.dev'))) {return $ctx->customWrapperAttributes(['class' => 'full-url']);}return $ctx;})
Select::make('Links')->options(['/images/1.png' => 'Picture 1','/images/2.png' => 'Picture 2',])->multiple()->afterFill(function(Select $ctx) {if(collect($ctx->toValue())->every(fn($value) => str_contains($value, 'cutcode.dev'))) {return $ctx->customWrapperAttributes(['class' => 'full-url']);}return $ctx;})
Методы onChange
С помощью методов onChangeMethod()
и onChangeUrl()
можно добавить логику при изменении значений полей.
Методы onChangeUrl()
или onChangeMethod()
присутствуют у всех полей, кроме полей отношений HasOne
и HasMany
.
onChangeUrl()
onChangeUrl(Closure $url,HttpMethod $method = HttpMethod::GET,array $events = [],?string $selector = null,?AsyncCallback $callback = null)
onChangeUrl(Closure $url,HttpMethod $method = HttpMethod::GET,array $events = [],?string $selector = null,?AsyncCallback $callback = null)
$url
- url запроса,$method
- метод асинхронного запроса,$events
- вызываемые AlpineJS события после успешного запроса,$selector
- selector элемента у которого будет изменяться контент,$callback
- js callback функция после получения ответа.
Switcher::make('Active')->onChangeUrl(fn() => '/endpoint')
Switcher::make('Active')->onChangeUrl(fn() => '/endpoint')
Если требуется заменить область с html после успешного запроса, вы можете в ответе вернуть HTML контент или json с ключом html.
Switcher::make('Active')->onChangeUrl(fn() => '/endpoint', selector: '#my-selector')
Switcher::make('Active')->onChangeUrl(fn() => '/endpoint', selector: '#my-selector')
onChangeMethod()
Метод onChangeMethod()
позволяет асинхронно вызывать метод ресурса или страницы при изменении поля без необходимости создавать дополнительные контроллеры.
onChangeMethod(string $method,array|Closure $params = [],?string $message = null,?string $selector = null,array $events = [],?AsyncCallback $callback = null,?PageContract $page = null,?ResourceContract $resource = null)
onChangeMethod(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
- selector элемента у которого будет изменяться контент,$events
- вызываемые AlpineJS события после успешного запроса,$callback
- js callback функция после получения ответа,$page
- страница содержащая метод,$resource
- ресурс содержащий метод.
Switcher::make('Active')->onChangeMethod('someMethod')
Switcher::make('Active')->onChangeMethod('someMethod')
use MoonShine\Laravel\MoonShineRequest;public function someMethod(MoonShineRequest $request): void{// Logic}
use MoonShine\Laravel\MoonShineRequest;public function someMethod(MoonShineRequest $request): void{// Logic}
Изменение render поля
Чтобы полностью изменить render поля, можно воспользоваться методом changeRender()
.
changeRender(Closure $callback)
changeRender(Closure $callback)
В данном поле Select
трансформируется в текст:
Select::make('Links')->options(['/images/1.png' => 'Picture 1','/images/2.png' => 'Picture 2',])->multiple()->changeRender(fn(?array $values, Select $ctx) => Text::make($ctx->getLabel())->fill(implode(',', $values)))
Select::make('Links')->options(['/images/1.png' => 'Picture 1','/images/2.png' => 'Picture 2',])->multiple()->changeRender(fn(?array $values, Select $ctx) => Text::make($ctx->getLabel())->fill(implode(',', $values)))
Методы для значений
Получение значение из исходного
Метод fromRaw()
позволяет добавить замыкание для получения итоговое значение из исходного.
/*** @param Closure(mixed $raw, static): mixed $callback* @return $this*/fromRaw(Closure $callback)
/*** @param Closure(mixed $raw, static): mixed $callback* @return $this*/fromRaw(Closure $callback)
use App\Enums\StatusEnum;use MoonShine\UI\Fields\Enum;Enum::make('Status')->attach(StatusEnum::class)->fromRaw(fn(string $raw, Enum $ctx) => StatusEnum::tryFrom($raw))
use App\Enums\StatusEnum;use MoonShine\UI\Fields\Enum;Enum::make('Status')->attach(StatusEnum::class)->fromRaw(fn(string $raw, Enum $ctx) => StatusEnum::tryFrom($raw))
Получения необработанного значения
Метод modifyRawValue()
позволяет добавить замыкание для получения необработанного значения.
/*** @param Closure(mixed $raw, mixed $data, static): mixed $callback* @return $this*/modifyRawValue(Closure $callback)
/*** @param Closure(mixed $raw, mixed $data, static): mixed $callback* @return $this*/modifyRawValue(Closure $callback)
use App\Enums\StatusEnum;use MoonShine\UI\Fields\Enum;Enum::make('Status')->attach(StatusEnum::class)->modifyRawValue(fn(StatusEnum $raw, Order $data, Enum $ctx) => $raw->value))
use App\Enums\StatusEnum;use MoonShine\UI\Fields\Enum;Enum::make('Status')->attach(StatusEnum::class)->modifyRawValue(fn(StatusEnum $raw, Order $data, Enum $ctx) => $raw->value))
Редактирование в режиме preview
Редактирование в режиме preview доступно для полей Text
, Number
, Checkbox
, Select
и Date
.
Для редактирования полей в режиме preview, например в таблице или в любом другом IterableComponent
, существуют следующие методы.
updateOnPreview
Метод updateOnPreview()
позволяет редактировать поле в режиме предварительного просмотра.
После внесения изменений (по событию onChange), значение поля будет сохранено для конкретного элемента.
updateOnPreview(?Closure $url = null,?ResourceContract $resource = null,mixed $condition = null,array $events = [])
updateOnPreview(?Closure $url = null,?ResourceContract $resource = null,mixed $condition = null,array $events = [])
$url
- (опционально) url запроса,$resource
- (опционально) ресурс содержащий updateOnPreview,$condition
- (опционально) условие установки поля в режим updateOnPreview,$events
- (опционально) вызываемые AlpineJS события после успешного запроса.
Параметры не являются обязательными, но должны быть заданы, если поле находится вне ресурса или же вы хотите указать полностью свой endpoint (тогда и ресурс не нужен).
Text::make('Name')->updateOnPreview()
Text::make('Name')->updateOnPreview()
withUpdateRow
withUpdateRow()
работает по аналогии с updateOnPreview()
, но при этом может полностью обновить строку в таблице без перезагрузки страницы.
withUpdateRow(string $component)
withUpdateRow(string $component)
$component
- имя компонента, в котором присутствует данная строка.
Text::make('Name')->withUpdateRow('index-table-post-resource')
Text::make('Name')->withUpdateRow('index-table-post-resource')
withUpdateRow()
может использовать все параметры updateOnPreview()
, например для изменения url запроса, для этого их необходимо вызвать вместе.
Text::make('Name')->updateOnPreview(url: '/my/url')->withUpdateRow()
Text::make('Name')->updateOnPreview(url: '/my/url')->withUpdateRow()
updateInPopover
Метод updateInPopover()
работает аналогично методу withUpdateRow()
, но теперь все значения для редактирования появляются в отдельном окне.
updateInPopover(string $component)
updateInPopover(string $component)
$component
- имя компонента, в котором присутствует данная строка.
Text::make('Name')->updateInPopover('index-table-post-resource')
Text::make('Name')->updateInPopover('index-table-post-resource')
Методы updateOnPreview()
, withUpdateRow()
и updateInPopover()
формируют нужные endpoints и передают методу setUpdateOnPreviewUrl()
, который работает с onChangeUrl().
Ассеты
Для добавления ассетов к полю можно использовать метод addAssets()
.
use Illuminate\Support\Facades\Vite;use MoonShine\AssetManager\Css;Text::make('Name')->addAssets([new Css(Vite::asset('resources/css/text-field.css'))])
use Illuminate\Support\Facades\Vite;use MoonShine\AssetManager\Css;Text::make('Name')->addAssets([new Css(Vite::asset('resources/css/text-field.css'))])
Если вы реализуете собственное поле, то объявить набор ассетов в нем можно двумя способами.
- Через метод
assets()
:
use MoonShine\AssetManager\Css;use MoonShine\AssetManager\Js;/*** @return list<AssetElementContract>*/protected function assets(): array{return [Js::make('/js/custom.js'),Css::make('/css/styles.css')];}
use MoonShine\AssetManager\Css;use MoonShine\AssetManager\Js;/*** @return list<AssetElementContract>*/protected function assets(): array{return [Js::make('/js/custom.js'),Css::make('/css/styles.css')];}
- Через метод
booted()
:
use MoonShine\AssetManager\Css;use MoonShine\AssetManager\Js;protected function booted(): void{parent::booted();$this->getAssetManager()->add(Css::make('/css/app.css'))->append(Js::make('/js/app.js'));}
use MoonShine\AssetManager\Css;use MoonShine\AssetManager\Js;protected function booted(): void{parent::booted();$this->getAssetManager()->add(Css::make('/css/app.css'))->append(Js::make('/js/app.js'));}
Трейт Macroable
Всем полям доступен трейт Illuminate\Support\Traits\Macroable
с методами mixin()
и macro()
.
С помощью этого трейта вы можете расширять возможности полей, добавляя в них новый функционал без использования наследования.
use MoonShine\UI\Fields\Field;Field::macro('myMethod', fn() => /*реализация*/)Text::make()->myMethod()
use MoonShine\UI\Fields\Field;Field::macro('myMethod', fn() => /*реализация*/)Text::make()->myMethod()
Field::mixin(new MyNewMethods())
Field::mixin(new MyNewMethods())
Реактивность
Метод reactive()
позволяет реактивно изменять поля.
reactive(?Closure $callback = null,bool $lazy = false,int $debounce = 0,int $throttle = 0,)
reactive(?Closure $callback = null,bool $lazy = false,int $debounce = 0,int $throttle = 0,)
$callback
- callback функция,$lazy
- отложенный вызов функции,$debounce
- время между вызовами функций (ms.),$throttle
- интервал вызова функций (ms.).
use MoonShine\UI\Collections\Fields;use MoonShine\UI\Components\FormBuilder;use MoonShine\UI\Fields\Text;FormBuilder::make()->name('my-form')->fields([Text::make('Title')->reactive(function(Fields $fields, ?string $value): Fields {return tap($fields, static fn ($fields) => $fields->findByColumn('slug')?->setValue(str($value ?? '')->slug()->value()));}),Text::make('Slug')->reactive()])
use MoonShine\UI\Collections\Fields;use MoonShine\UI\Components\FormBuilder;use MoonShine\UI\Fields\Text;FormBuilder::make()->name('my-form')->fields([Text::make('Title')->reactive(function(Fields $fields, ?string $value): Fields {return tap($fields, static fn ($fields) => $fields->findByColumn('slug')?->setValue(str($value ?? '')->slug()->value()));}),Text::make('Slug')->reactive()])
В данном пример реализовано формирование slug-поля на основе заголовка. Slug будет генерироваться в процессе ввода текста.
Реактивное поле может менять состояние других полей, но не изменяет свое состояние!
Для изменения состояния поля инициирующего реактивность удобно воспользоваться параметрами callback-функции.
use MoonShine\UI\Fields\Field;use MoonShine\UI\Fields\Select;use MoonShine\UI\Collections\Fields;Select::make('Category', 'category_id')->reactive(function(Fields $fields, ?string $value, Field $field, array $values): Fields {$field->setValue($value);return tap($fields, static fn ($fields) =>$fields->findByColumn('article_id')?->options(Article::where('category_id', $value)->get()->pluck('title', 'id')->toArray()););})
use MoonShine\UI\Fields\Field;use MoonShine\UI\Fields\Select;use MoonShine\UI\Collections\Fields;Select::make('Category', 'category_id')->reactive(function(Fields $fields, ?string $value, Field $field, array $values): Fields {$field->setValue($value);return tap($fields, static fn ($fields) =>$fields->findByColumn('article_id')?->options(Article::where('category_id', $value)->get()->pluck('title', 'id')->toArray()););})
Динамическое отображение
Поля можно скрывать или показывать динамически, в зависимости от значений других полей в реальном времени без перезагрузки страницы и запросов к серверу.
Для этого используются методы showWhen()
и showWhenDate()
.
Метод showWhen
Метод showWhen()
позволяет задать условие отображения поля в зависимости от значения другого поля.
showWhen(string $column,mixed $operator = null,mixed $value = null)
showWhen(string $column,mixed $operator = null,mixed $value = null)
$column
- имя поля, от которого зависит отображение,$operator
- оператор сравнения (необязательный),$value
- значение для сравнения.
Text::make('Name')->showWhen('category_id', 1)
Text::make('Name')->showWhen('category_id', 1)
В этом примере поле "Name" будет отображаться только если значение поля "category_id" равно 1.
Если в функции showWhen
передается только два параметра, то по умолчанию используется оператор '='
.
Text::make('Name')->showWhen('category_id', 'in', [1, 2, 3])
Text::make('Name')->showWhen('category_id', 'in', [1, 2, 3])
В этом примере поле "Name" будет отображаться только если значение поля "category_id" равно 1, 2 или 3.
Когда на поле присутствует условие showWhen
, то при скрытии этого поля, на его DOM элемент устанавливается значение display:none
и удаляется атрибут name, чтобы значение этого скрытого поля не попадало в итоговый запрос.
Если вы не хотите, чтобы атрибут name
удалялся, необходимо в вашем ресурсе установить флаг $submitShowWhen
в значение true
.
class ArticleResource extends ModelResource{protected bool $submitShowWhen = true;// ...}
class ArticleResource extends ModelResource{protected bool $submitShowWhen = true;// ...}
Метод showWhenDate
Метод showWhenDate()
позволяет задать условие отображения поля в зависимости от значения поля типа date.
Логика для работы с датами была вынесена в отдельный метод из-за специфики конвертации и сравнения типа date и datetime на backend и frontent.
showWhenDate(string $column,mixed $operator = null,mixed $value = null)
showWhenDate(string $column,mixed $operator = null,mixed $value = null)
$column
- имя поля с датой, от которого зависит отображение,$operator
- оператор сравнения (необязательный),$value
- значение даты для сравнения.
Text::make('Content')->showWhenDate('created_at', '>', '2024-09-15 10:00')
Text::make('Content')->showWhenDate('created_at', '>', '2024-09-15 10:00')
В этом примере поле "Content" будет отображаться только если значение поля "created_at" больше '2024-09-15 10:00'.
Если в функции showWhenDate
передается только два параметра, то по умолчанию используется оператор '='
.
Вы можете использовать любой формат даты, который может быть распознан функцией strtotime()
.
Вложенные поля
Методы showWhen()
и showWhenDate()
поддерживают работу с вложенными полями, например для работы с полем Json
.
Для обращения к вложенным полям используется точечная нотация.
Text::make('Parts')->showWhen('attributes.1.size', '!=', 2)
Text::make('Parts')->showWhen('attributes.1.size', '!=', 2)
В этом примере поле "Parts" будет отображаться только если значение вложенного поля "size" во втором элементе массива "attributes" не равно 2.
showWhen()
работает и для вложенных полей типа Json
:
Json::make('Attributes', 'attributes')->fields([Text::make('Size'),Text::make('Parts')->showWhen('category_id', 3),Json::make('Settings', 'settings')->fields([Text::make('Width')->showWhen('category_id', 3),Text::make('Height'),])]),
Json::make('Attributes', 'attributes')->fields([Text::make('Size'),Text::make('Parts')->showWhen('category_id', 3),Json::make('Settings', 'settings')->fields([Text::make('Width')->showWhen('category_id', 3),Text::make('Height'),])]),
В данном примере весь столбец Parts
внутри attributes
и весь столбец Width
внутри attributes.[n].settings
будет отображаться только если значение поля category_id
равно 3.
Множественные условия
Методы showWhen()
и showWhenDate()
могут быть вызваны несколько раз для одного поля, что позволяет задать несколько условий отображения.
BelongsTo::make('Category', 'category', resource: CategoryResource::class)->showWhenDate('created_at', '>', '2024-08-05 10:00')->showWhenDate('created_at', '<', '2024-08-05 19:00')
BelongsTo::make('Category', 'category', resource: CategoryResource::class)->showWhenDate('created_at', '>', '2024-08-05 10:00')->showWhenDate('created_at', '<', '2024-08-05 19:00')
В этом примере поле "Category" будет отображаться только если значение поля "created_at" находится в диапазоне между '2024-08-05 10:00' и '2024-08-05 19:00'.
При использовании нескольких условий они объединяются логическим "И" (AND). Поле будет отображаться только если выполняются все заданные условия.
Поддерживаемые операторы
=
!=
>
<
>=
<=
in
not in
Оператор in
проверяет, содержится ли значение в массиве.
Оператор not in
проверяет, не содержится ли значение в массиве.
Кастомное поле
Вы можете создать собственное поле, со своим view и логикой и использовать его в административной панели MoonShine. Для этого воспользуйтесь командой:
php artisan moonshine:field
php artisan moonshine:field
О всех поддерживаемых опциях можно узнать в разделе Команды.