marshmallow / nova-multiselect-field
A multiple select field for Laravel Nova.
Fund package maintenance!
outl1ne
Requires
- php: >=8.0
- laravel/nova: ^4.27
- nova-kit/nova-packages-tool: ^1.12
- outl1ne/nova-translations-loader: ^5.0
Requires (Dev)
- nova-kit/nova-devtool: ^1.2.1
- dev-master
- v5.1.0
- v5.0.2
- v5.0.1
- v5.0.0
- 4.0.5
- 4.0.4
- 4.0.3
- 4.0.2
- 4.0.1
- 4.0.0
- 3.0.1
- 3.0.0
- v2.4.0
- 2.3.13
- 2.3.12
- 2.3.11
- 2.3.10
- 2.3.9
- 2.3.8
- 2.3.7
- 2.3.6
- 2.3.5
- 2.3.4
- 2.3.3
- 2.3.2
- 2.3.1
- 2.3.0
- 2.2.1
- 2.2.0
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.7
- 2.0.6
- 2.0.5
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 1.11.5
- 1.11.4
- 1.11.3
- 1.11.2
- 1.11.1
- 1.11.0
- 1.10.3
- 1.10.2
- 1.10.1
- 1.10.0
- 1.9.9
- 1.9.8
- 1.9.7
- 1.9.6
- 1.9.5
- 1.9.4
- 1.9.3
- 1.9.2
- 1.9.1
- 1.9.0
- 1.8.2
- 1.8.1
- 1.8.0
- 1.7.4
- 1.7.3
- 1.7.2
- 1.7.1
- 1.7.0
- 1.6.2
- 1.6.1
- 1.6.0
- 1.5.0
- 1.4.0
- 1.3.5
- 1.3.4
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.0
- 1.1.6
- 1.1.5
- 1.1.4
- 1.1.3
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.0
- dev-merge-upstream
- dev-development
- dev-nova4
- dev-dependabot/npm_and_yarn/follow-redirects-1.14.8
This package is auto-updated.
Last update: 2024-11-30 15:04:08 UTC
README
This Laravel Nova package adds a multiselect to Nova's arsenal of fields.
Requirements
php: >=8.0
laravel/nova: ^4.1
Features
- Multi- and singleselect with search
- Asynchronous search
- Reordering functionality with drag & drop
- Dependency on other Multiselect instances
- Distinct values between multiple multiselects
- Fully compatible with light and dark modes
Screenshots
Installation
Install the package in a Laravel Nova project via Composer:
composer require marshmallow/nova-multiselect-field
Usage
The field is used similarly to Nova's native Select field. The field type in the database should be text-based (ie string
, text
or varchar
), selected values are stored as a stringified JSON array.
use Outl1ne\MultiselectField\Multiselect; public function fields(Request $request) { return [ Multiselect::make('Football teams') ->options([ 'liverpool' => 'Liverpool FC', 'tottenham' => 'Tottenham Hotspur', ]) // Optional: ->placeholder('Choose football teams') // Placeholder text ->max(4) // Maximum number of items the user can choose ->saveAsJSON() // Saves value as JSON if the database column is of JSON type ->optionsLimit(5) // How many items to display at once ->reorderable() // Allows reordering functionality ->singleSelect() // If you want a searchable single select field ->distinct('football') // Disables values used by other multiselects in same distinct group ->taggable() // Possible to add values ("tags") on the fly // Async model querying Multiselect::make('Artists') ->asyncResource(Artist::class), // If you want a custom search, create your own endpoint: ->api('/api/multiselect/artists?something=false', Artist::class), ]; }
Option groups
Option groups are supported. Their syntax is the same as Laravel's option group syntax.
In this example (from Nova docs), all values are grouped by the group
key:
->options([ 'MS' => ['label' => 'Small', 'group' => 'Men Sizes'], 'MM' => ['label' => 'Medium', 'group' => 'Men Sizes'], 'WS' => ['label' => 'Small', 'group' => 'Women Sizes'], 'WM' => ['label' => 'Medium', 'group' => 'Women Sizes'], ])
Dependencies
You can make a Multiselect depend on another by using optionsDependOn
. The value from the optionsDependOn
Multiselect has to be the key to the options and the value must be a key-value dictionary of options as usual.
Usage:
Multiselect::make('Country', 'country') ->options([ 'IT' => 'Italy', 'SG' => 'Singapore', ]), Multiselect::make('Language', 'language') ->optionsDependOn('country', [ 'IT' => [ 'it' => 'Italian', ], 'SG' => [ 'en' => 'English', 'ms' => 'Malay', 'zh' => 'Chinese', ] ]), // Optionally define max number of values ->optionsDependOnMax([ 'IT' => 1, 'SG' => 3, ])
Belongs-To-Many
You can use this field for BelongsToMany
relationship selection.
// Add your BelongsToMany relationship to your model: public function categories() { return $this->belongsToMany(\App\Models\Category::class); } // Add the field to your Resource for asynchronous option querying: Multiselect::make('Categories', 'categories') ->belongsToMany(\App\Nova\Resources\Category::class), // Alternatively, you can set the second argument to 'false' to // query the options on page load and prevent the user from having // to first type in order to view the available options. Note: Not // recommended for unbounded relationship row counts. Multiselect::make('Categories', 'categories') ->belongsToMany(\App\Nova\Resources\Category::class, false),
Options
Possible options you can pass to the field using the option name as a function, ie ->placeholder('Choose peanuts')
.
Localization
The translations file can be published by using the following publish command:
php artisan vendor:publish --provider="Outl1ne\MultiselectField\FieldServiceProvider" --tag="translations"
You can then edit the strings to your liking.
Overwriting the detail field
You can overwrite the detail view value component to customize it as you see fit.
Create a new component for NovaMultiselectDetailFieldValue
and register it in your app.js
. The component receives two props: field
and values
. The values
prop is an array of selected labels.
// in NovaMultiselectDetailFieldValue.vue <template> <div class="relative rounded-lg bg-white shadow border border-60" v-if="values"> <div class="overflow-hidden rounded-b-lg rounded-t-lg"> <div class="border-b border-50 cursor-text font-mono text-sm py-2 px-4" v-for="(value, i) of values" :key="i"> {{ value }} </div> </div> </div> <div v-else>—</div> </template> <script> export default { props: ['field', 'values'], }; </script>
// in app.js import NovaMultiselectDetailFieldValue from './NovaMultiselectDetailFieldValue'; Nova.booting((Vue, router, store) => { Vue.component('nova-multiselect-detail-field-value', NovaMultiselectDetailFieldValue); });
Overwriting the form tag field
You can overwrite the tag template in the form-field component to customize it as you see fit.
Create a new component for FormFieldTag
and register it in your app.js
. The component receives two props: option
and remove
. The option
prop is an object with, for example, the label
.
// in FormFieldTag.vue <template> <span class="multiselect__tag"> <span>{{ option.label.trim() }}</span> <i class="multiselect__tag-icon" @click="remove(option)"></i> </span> </template> <script> export default { props: ['option', 'remove'], }; </script>
// in app.js import FormFieldTag from './FormFieldTag'; Nova.booting((Vue, router, store) => { Vue.component('form-multiselect-field-tag', FormFieldTag); });
Credits
License
This project is open-sourced software licensed under the MIT license.