marshmallow / nova-multiselect-field
A multiple select field for Laravel Nova.
Installs: 6 720
Dependents: 3
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 0
Open Issues: 0
Requires
- php: >=8.0
- laravel/nova: ^4.27|^5.0
- nova-kit/nova-packages-tool: ^1.12|^2.0
- outl1ne/nova-translations-loader: ^5.0
Requires (Dev)
- nova-kit/nova-devtool: ^1.2.1
README
This Laravel Nova package adds a multiselect to Nova's arsenal of fields.
Important
This package was originally forked from outl1ne/nova-multiselect-field. Since we were making many opinionated changes, we decided to continue development in our own version rather than submitting pull requests that might not benefit all users of the original package. You’re welcome to use this package, we’re actively maintaining it. If you encounter any issues, please don’t hesitate to reach out.
Requirements
php: >=8.1
laravel/nova: ^5.0
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
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 Marshmallow\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="Marshmallow\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.