Form and events
Upon a successful request, the form updates the table and resets the values.
Block::make([ FormBuilder::make(route('form-table.store')) ->fields([ Text::make('Title') ]) ->name('main-form') ->async(asyncEvents: ['table-updated-main-table','form-reset-main-form'])]), TableBuilder::make() ->fields([ ID::make(), Text::make('Title'), Textarea::make('Body'), ]) ->creatable() ->items(Post::query()->paginate()) ->name('main-table') ->async()
Let's also look at how to add your own events
<div x-data="" @my-event.window="alert()"></div>
<div x-data="my" @my-event.window="asyncRequest"></div> <script> document.addEventListener("alpine:init", () => { Alpine.data("my", () => ({ init() { }, asyncRequest() { this.$event.preventDefault() // this.$el // this.$root } })) })</script>
FormBuilder::make(route('form-table.store')) ->fields([ Text::make('Title') ]) ->name('main-form') ->async(asyncEvents: ['my-event'])
View component with AlpineJs
We also recommend that you familiarize yourself with AlpineJs and use the full power of this js framework.
You can use its reactivity, let's see how to conveniently create a component.
<div x-data="myComponent"></div> <script> document.addEventListener("alpine:init", () => { Alpine.data("myComponent", () => ({ init() { }, })) })</script>
Vite build connection
Let's add one compiled using Vite build.
use Illuminate\Support\Facades\Vite; class MoonShineServiceProvider extends MoonShineApplicationServiceProvider{//... public function boot(): void{ parent::boot(); moonShineAssets()->add([ Vite::asset('resources/css/app.css'), Vite::asset('resources/js/app.js'), ]); } //...}
Custom buttons
Let's add custom buttons to the index table.
public function indexButtons(): array{ $resource = new CommentResource(); return [ ActionButton::make('Custom button', static fn ($data): string => to_page( page: $resource->formPage(), resource: $resource, params: ['resourceItem' => $data->getKey()] )) ];}
HasOne through the Template field
An example of implementing the HasOne relationship through the Template
field.
use MoonShine\Fields\Template; //... public function fields(): array{ return [ Template::make('Comment') ->changeFill(fn (Article $data) => $data->comment) ->changePreview(fn($data) => $data?->id ?? '-') ->fields((new CommentResource())->getFormFields()) ->changeRender(function (?Comment $data, Template $field) { $fields = $field->preparedFields(); $fields->fill($data?->toArray() ?? [], $data ?? new Comment()); return Components::make($fields); }) ->onAfterApply(function (Article $item, array $value) { $item->comment()->updateOrCreate([ 'id' => $value['id'] ], $value); return $item; }) ];} //...
Changing breadcrumbs from a resource
You can change page breadcrumbs directly from the resource.
namespace App\MoonShine\Resources; use App\Models\Post;use MoonShine\Resources\ModelResource; class PostResource extends ModelResource{ //... protected function onBoot(): void { $this->formPage() ->setBreadcrumbs([ '#' => $this->title() ]); } //...}
Index page via CardsBuilder
Let's change the display of elements on the index page through the CardsBuilder component.
class MoonShineUserIndexPage extends IndexPage{ public function listComponentName(): string { return 'index-cards'; } public function listEventName(): string { return 'cards-updated'; } protected function itemsComponent(iterable $items, Fields $fields): MoonShineRenderable { return CardsBuilder::make($items, $fields) ->cast($this->getResource()->getModelCast()) ->name($this->listComponentName()) ->async() ->overlay() ->title('email') ->subtitle('name') ->url(fn ($user) => $this->getResource()->formPageUrl($user)) ->thumbnail(fn ($user) => asset($user->avatar)) ->buttons($this->getResource()->getIndexItemButtons()); }}
Сортировка для CardsBuilder
Let's create a sorting for the CardsBuilder component:
Select::make('Sorts')->options([ 'created_at' => 'Date', 'id' => 'ID',]) ->onChangeMethod('reSort', events: ['cards-updated-cards']) ->setValue(session('sort_column') ?: 'created_at'), CardsBuilder::make( items: Article::query()->with('author') ->when( session('sort_column'), fn($q) => $q->orderBy(session('sort_column'), session('sort_direction', 'asc')), fn($q) => $q->latest() ) ->paginate()) ->name('cards') ->async() ->cast(ModelCast::make(Article::class)) ->title('title') ->url(fn($data) => (new ArticleResource())->formPageUrl($data)) ->overlay() ->columnSpan(4) , // ... public function reSort(MoonShineRequest $request): void{ session()->put('sort_column', $request->get('value')); session()->put('sort_direction', 'ASC');}
updateOnPreview for pivot fields
Implementation via asyncMethod of the method for changing the pivot field on the index page:
public function fields(): array{ return [ Grid::make([ Column::make([ ID::make()->sortable(), Text::make('Team title')->required(), Number::make('Team number'), BelongsTo::make('Tournament', resource: new TournamentResource()) ->searchable(), ]), Column::make([ BelongsToMany::make('Users', resource: new UserResource()) ->fields([ Switcher::make('Approved') ->updateOnPreview(MoonShineRouter::asyncMethodClosure( 'updatePivot', params: fn($data) => ['parent' => $data->pivot->tournamen_team_id] )), ]) ->searchable(), ]) ]) ];} public function updatePivot(MoonShineRequest $request): MoonShineJsonResponse{ $item = TournamentTeam::query() ->findOrFail($request->get('parent')); $column = (string) $request->str('field')->remove('pivot.'); $item-> users()->updateExistingPivot($request->get('resourceItem'), [ $column => $request->get('value'), ]); return MoonShineJsonResponse::make() ->toast('Success');}
Parent ID in HasMany
The HasMany connection stores file data that needs to be saved in a directory by parent id.
use App\Models\PostImage;use MoonShine\Fields\ID;use MoonShine\Fields\Image;use MoonShine\Fields\Relationships\BelongsTo;use MoonShine\Resources\ModelResource;use MoonShine\Traits\Resource\ResourceWithParent; class PostImageResource extends ModelResource{ use ResourceWithParent; public string $model = PostImage::class; protected function getParentResourceClassName(): string { return PostResource::class; } protected function getParentRelationName(): string { return 'post'; } public function fields(): array { return [ ID::make(), Image::make('Path') ->when( $parentId = $this->getParentId(), fn(Image $image) => $image->dir('post_images/'.$parentId) ) , BelongsTo::make('Post', 'post', resource: new PostResource()) ]; } //...}