Basics
The BelongsToMany field is designed to work with the relation of the same name in Laravel and includes all the basic methods.
To create this field, use the static make()
method.
BelongsToMany::make( Closure|string $label, ?string $relationName = null, Closure|string|null $formatted = null, ?ModelResource $resource = null)
-
$label
- label, field header, -
$relationName
- name of the relationship, -
$formatted
- a closure or field in a related table to display values, -
$resource
- the model resource referenced by the relation.
The presence of the model resource referenced by the relation is mandatory! The resource also needs to be registered with the service provider MoonShineServiceProvider in the method menu()
or resources()
. Otherwise, there will be a 404 error.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', 'categories', resource: new CategoryResource()) ];}
If you do not specify $relationName
, then the relation name will be determined automatically based on $label
.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ];} //...
You can omit $resource
if the model resource matches the name of the relationship.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', 'categories') ];} //...
By default, a field in the related table is used to display the value. which is specified by the $column
property in the model resource.
The $formatted
argument allows you to override this..
namespace App\MoonShine\Resources; use MoonShine\Resources\ModelResource; class CategoryResource extends ModelResource{ //... public string $column = 'title'; //...}
If you need to specify a more complex value to display, then the $formatted
argument can be passed a callback function.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make( 'Categories', 'categories', fn($item) => "$item->id. $item->title" ) ];} //...
Column header
By default, the table column header uses the property $title
of the relationship model resource.
The columnLabel()
method allows you to override the title.
columnLabel(string $label)
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->columnLabel('Title') ];} //...
Pivot
The fields()
method is used to implement pivot fields in the BelongsToMany relationship.
fields(Fields|Closure|array $fields)
use MoonShine\Fields\Relationships\BelongsToMany;use MoonShine\Fields\Text; //... public function fields(): array{ return [ BelongsToMany::make('Contacts', resource: new ContactResource()) ->fields([ Text::make('Contact', 'text'), ]) ];} //...
The relationship must specify which pivot fields are used in the staging table! More details in the official documentation Laravel.
Creating a Relationship Object
The creatable()
method allows you to create a new relation object through a modal window.
creatable( Closure|bool|null $condition = null, ?ActionButton $button = null,)
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->creatable() ];} //...
You can customize the create button by passing the button parameter to the method.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->creatable( button: ActionButton::make('Custom button', '') ) ];} //...
Select
The BelongsToMany field can be displayed as a drop-down list, To do this, you need to use the selectMode()
method.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->selectMode() ];} //...
Options
All choices options are available to change via data attributes:
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Countries', resource: new CountryResource()) ->selectMode() ->customAttributes([ 'data-max-item-count' => 2 ]) ];}
For more details please contact Choices.
Placeholder
The placeholder()
method allows you to set placeholder attribute on the field.
placeholder(string $value)
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Countries', 'countries') ->nullable() ->placeholder('Countries') ];} //...
The placeholder()
method is only used if the field is displayed as a dropdown list selectMode()
!
Tree
The tree()
method allows you to display values as a tree with checkboxes, for example, for categories that have nesting. The method must be passed a column in the database on which the tree will be built.
tree(string $parentColumn)
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->tree('parent_id') ];} //...
Preview
By default, preview will display the field as a table.
To change the display in preview you can use the following methods.
onlyCount
The onlyCount()
method allows you to display only the number of selected values in preview.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->onlyCount() ];} //...
inLine
The inLine()
method allows you to display field values as a line.
inLine(string $separator = '', Closure|bool $badge = false, ?Closure $link = null)
You can pass optional parameters to the method:
-
separator
- separator between elements; -
badge
- closure or boolean value, responsible for displaying elements as badge; -
$link
- a closure that should return url links or components.
When passing the boolean value true to the badge
parameter, the color will be used Primary . To change the color displayed by badge
, use closure and return the Badge::make()
component.
use MoonShine\Components\Link;use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->inLine( separator: ' ', badge: fn($model, $value) => Badge::make($value, 'color'), link: fn(Category $category, $value, $field) => Link::make( (new CategoryResource())->detailPageUrl($category), $value ) ) ];} //...
Link only
The onlyLink()
method will allow you to display the relationship as a link with the number of elements.
onlyLink(?string $linkRelation = null, Closure|bool $condition = null)
You can pass optional parameters to the method:
-
linkRelation
- link to the relationship; -
condition
- closure or boolean value, responsible for displaying the relationship as a link.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->onlyLink('category') ];}
linkRelation
The linkRelation
parameter allows you to create a link to a relation with a parent resource binding.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->onlyLink('category') ];} //...
condition
The condition
parameter via a closure will allow you to change the display method depending on the conditions.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->onlyLink(condition: function (int $count, Field $field): bool { return $count > 10; }) ];} //...
Query for values
The valuesQuery()
method allows you to change the query for obtaining values.
valuesQuery(Closure $callback)
use Illuminate\Contracts\Database\Eloquent\Builder;use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Countries', 'countries', resource: new CountryResource()) ->valuesQuery(fn(Builder $query, Field $field) => $query->where('active', true)) ];}
Asynchronous search
To implement asynchronous search for values, use the asyncSearch()
method.
asyncSearch( string $asyncSearchColumn = null, int $asyncSearchCount = 15, ?Closure $asyncSearchQuery = null, ?Closure $asyncSearchValueCallback = null, ?string $associatedWith = null, ?string $url = null, bool $replaceQuery = false,)
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Countries', 'countries', resource: new CountryResource()) ->asyncSearch() ];} //...
The search will be carried out using the resource relationship field column
. By default column=id
You can pass parameters to the asyncSearch()
method:
-
$asyncSearchColumn
- the field in which the search takes place; -
$asyncSearchCount
- number of elements in the search results; -
$asyncSearchQuery
- callback-function for filtering values; -
$asyncSearchValueCallback
- callback-function for customizing output; -
$associatedWith
- the field with which to establish a connection; -
$url
- url to process the asynchronous request, -
$replaceQuery
- replace query.
use Illuminate\Contracts\Database\Eloquent\Builder;use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Countries', 'countries', resource: new CountryResource()) ->asyncSearch( 'title', 10, asyncSearchQuery: function (Builder $query, Request $request, Field $field) { return $query->where('id', '!=', 2); }, asyncSearchValueCallback: function ($country, Field $field) { return $country->id . ' | ' . $country->title; }, '/async' ) ];} //...
When building a query in asyncSearchQuery()
, you can use the current form values. To do this, you need to pass Request
to the callback function.
use Illuminate\Contracts\Database\Eloquent\Builder;use Illuminate\Http\Request;use MoonShine\Fields\Relationships\BelongsToMany;use MoonShine\Fields\Select; //... public function fields(): array{ return [ Select::make('Country', 'country_id'), BelongsToMany::make('Cities', 'cities', resource: new CityResource()) ->asyncSearch( 'title', asyncSearchQuery: function (Builder $query, Request $request, Field $field): Builder { return $query->where('country_id', $request->get('country_id')); } ) ];} //...
When building a query in asyncSearchQuery()
, the original state of the builder is preserved.
If you need to replace it with your builder, then use the replaceQuery
flag.
use Illuminate\Contracts\Database\Eloquent\Builder;use Illuminate\Http\Request;use MoonShine\Fields\Relationships\BelongsToMany;use MoonShine\Fields\Select; //... public function fields(): array{ return [ Select::make('Country', 'country_id'), BelongsToMany::make('Cities', 'cities', resource: new CityResource()) ->asyncSearch( 'title', asyncSearchQuery: function (Builder $query, Request $request, Field $field): Builder { return $query->where('country_id', $request->get('country_id')); }, replaceQuery: true ) ];} //...
Requests must be customized using the asyncSearch()
method. Don't use valuesQuery()
!
Related fields
To associate select values between fields, you can use the associatedWith()
method.
associatedWith(string $column, ?Closure $asyncSearchQuery = null)
-
$column
- the field with which the connection is established; -
$asyncSearchQuery
- callback function for filtering values.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Cities', 'cities', resource: new CityResource()) ->associatedWith('country_id') ];}
[TIP] For more complex setup, you can use
asyncSearch()
.
Values with picture
The withImage()
method allows you to add an image to a value.
withImage( string $column, string $disk = 'public', string $dir = '')
-
$column
- field with an image; -
$disk
- file system disk; -
$dir
- directory relative to the root of the disk.
use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make(Countries, resource: new CountryResource()) ->withImage('thumb', 'public', 'countries')->selectMode() ];} //...
Buttons
The buttons()
method allows you to add additional buttons to the BelongsToMany field.
buttons(array $buttons)
use MoonShine\ActionButtons\ActionButton;use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->buttons([ ActionButton::make('Check all', '') ->onClick(fn() => 'checkAll', 'prevent'), ActionButton::make('Uncheck all', '') ->onClick(fn() => 'uncheckAll', 'prevent') ]) ];}
withCheckAll
The withCheckAll()
method allows you to add checkAll/uncheckAll buttons to the BelongsToMany field similar to the previous example.
use MoonShine\ActionButtons\ActionButton;use MoonShine\Fields\Relationships\BelongsToMany; //... public function fields(): array{ return [ BelongsToMany::make('Categories', resource: new CategoryResource()) ->withCheckAll() ];} //...