mirror of
https://github.com/filamentphp/filament.git
synced 2026-10-25 10:04:54 +08:00
Add option group support
This commit is contained in:
@@ -196,6 +196,26 @@ class FieldsDemo extends Component implements HasForms
|
||||
'livewire' => 'Laravel Livewire',
|
||||
]),
|
||||
]),
|
||||
Group::make()
|
||||
->id('groupedSelect')
|
||||
->extraAttributes([
|
||||
'class' => 'px-16 pt-16 pb-96 max-w-xl',
|
||||
])
|
||||
->schema([
|
||||
Select::make('groupedSelect')
|
||||
->label('Status')
|
||||
->searchable()
|
||||
->options([
|
||||
'In Process' => [
|
||||
'draft' => 'Draft',
|
||||
'reviewing' => 'Reviewing',
|
||||
],
|
||||
'Reviewed' => [
|
||||
'published' => 'Published',
|
||||
'rejected' => 'Rejected',
|
||||
],
|
||||
]),
|
||||
]),
|
||||
Group::make()
|
||||
->id('createSelectOption')
|
||||
->extraAttributes([
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
@@ -425,6 +425,20 @@ export default {
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
},
|
||||
},
|
||||
'forms/fields/select/grouped': {
|
||||
url: 'forms/fields',
|
||||
selector: '#groupedSelect',
|
||||
viewport: {
|
||||
width: 1920,
|
||||
height: 640,
|
||||
deviceScaleFactor: 3,
|
||||
},
|
||||
before: async (page) => {
|
||||
await page.click('#groupedSelect .choices')
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
},
|
||||
},
|
||||
'forms/fields/select/create-option': {
|
||||
url: 'forms/fields',
|
||||
selector: '#createSelectOption',
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -18,22 +18,6 @@ Select::make('status')
|
||||
])
|
||||
```
|
||||
|
||||
You can optionally also add groups by adding an array instead of a label in the options:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Select;
|
||||
|
||||
Select::make('status')
|
||||
->options([
|
||||
'In Process' => [
|
||||
'draft' => 'Draft',
|
||||
'reviewing' => 'Reviewing',
|
||||
],
|
||||
'published' => 'Published',
|
||||
])
|
||||
```
|
||||
|
||||
|
||||
<AutoScreenshot name="forms/fields/select/simple" alt="Select" version="3.x" />
|
||||
|
||||
## Searching options
|
||||
@@ -112,6 +96,29 @@ Select::make('technologies')
|
||||
->getOptionLabelsUsing(fn (array $values): array => Technology::whereIn('id', $values)->pluck('name', 'id')->toArray()),
|
||||
```
|
||||
|
||||
## Grouping options
|
||||
|
||||
You can group options together under a label, to organize them better. To do this, you can pass an array of groups to `options()` or wherever you would normally pass an array of options. The keys of the array are used as group labels, and the values are arrays of options in that group:
|
||||
|
||||
```php
|
||||
use Filament\Forms\Components\Select;
|
||||
|
||||
Select::make('status')
|
||||
->searchable()
|
||||
->options([
|
||||
'In Process' => [
|
||||
'draft' => 'Draft',
|
||||
'reviewing' => 'Reviewing',
|
||||
],
|
||||
'Reviewed' => [
|
||||
'published' => 'Published',
|
||||
'rejected' => 'Rejected',
|
||||
],
|
||||
])
|
||||
```
|
||||
|
||||
<AutoScreenshot name="forms/fields/select/grouped" alt="Grouped select" version="3.x" />
|
||||
|
||||
## Integrating with an Eloquent relationship
|
||||
|
||||
> If you're building a form inside your Livewire component, make sure you have set up the [form's model](../adding-a-form-to-a-livewire-component#setting-a-form-model). Otherwise, Filament doesn't know which model to use to retrieve the relationship from.
|
||||
|
||||
@@ -170,5 +170,6 @@ select:not(.choices) {
|
||||
}
|
||||
|
||||
.choices__group {
|
||||
@apply p-2 pt-6 text-gray-400 first:pt-2 dark:text-gray-500;
|
||||
@apply p-2 text-gray-400 first:pt-2 dark:text-gray-500;
|
||||
@apply pt-4 first:pt-2 !important;
|
||||
}
|
||||
|
||||
@@ -57,15 +57,15 @@
|
||||
@foreach ($getOptions() as $value => $label)
|
||||
@if (is_array($label))
|
||||
<optgroup label="{{ $value }}">
|
||||
@foreach ($label as $v => $l)
|
||||
@foreach ($label as $groupedValue => $groupedLabel)
|
||||
<option
|
||||
@disabled($isOptionDisabled($v, $l))
|
||||
value="{{ $v }}"
|
||||
@disabled($isOptionDisabled($groupedValue, $groupedLabel))
|
||||
value="{{ $groupedValue }}"
|
||||
>
|
||||
@if ($isHtmlAllowed)
|
||||
{!! $l !!}
|
||||
{!! $groupedLabel !!}
|
||||
@else
|
||||
{{ $l }}
|
||||
{{ $groupedLabel }}
|
||||
@endif
|
||||
</option>
|
||||
@endforeach
|
||||
|
||||
@@ -10,12 +10,12 @@ use Illuminate\Support\Collection;
|
||||
trait HasOptions
|
||||
{
|
||||
/**
|
||||
* @var array<string> | Arrayable | string | Closure | null
|
||||
* @var array<string | array<string>> | Arrayable | string | Closure | null
|
||||
*/
|
||||
protected array | Arrayable | string | Closure | null $options = null;
|
||||
|
||||
/**
|
||||
* @param array<string> | Arrayable | string | Closure | null $options
|
||||
* @param array<string | array<string>> | Arrayable | string | Closure | null $options
|
||||
*/
|
||||
public function options(array | Arrayable | string | Closure | null $options): static
|
||||
{
|
||||
@@ -25,7 +25,7 @@ trait HasOptions
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
* @return array<string | array<string>>
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
|
||||
@@ -18,7 +18,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||
use Illuminate\Database\Query\JoinClause;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Validation\Rules\Exists;
|
||||
@@ -119,11 +118,25 @@ class Select extends Field implements Contracts\HasAffixActions, Contracts\HasNe
|
||||
});
|
||||
|
||||
$this->getOptionLabelUsing(static function (Select $component, $value): ?string {
|
||||
if (array_key_exists($value, $options = $component->getOptions())) {
|
||||
return $options[$value];
|
||||
$options = $component->getOptions();
|
||||
|
||||
foreach ($options as $groupedOptions) {
|
||||
if (! is_array($groupedOptions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! array_key_exists($value, $groupedOptions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return $groupedOptions[$value];
|
||||
}
|
||||
|
||||
return $value;
|
||||
if (! array_key_exists($value, $options)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $options[$value];
|
||||
});
|
||||
|
||||
$this->getOptionLabelsUsing(static function (Select $component, array $values): array {
|
||||
@@ -132,12 +145,20 @@ class Select extends Field implements Contracts\HasAffixActions, Contracts\HasNe
|
||||
$labels = [];
|
||||
|
||||
foreach ($values as $value) {
|
||||
foreach ($options as $group => $option) {
|
||||
if (is_array($option) && Arr::has($option, $value)) {
|
||||
Arr::set($labels, "$group.$value", $option[$value]);
|
||||
continue 2;
|
||||
foreach ($options as $groupedOptions) {
|
||||
if (! is_array($groupedOptions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! array_key_exists($value, $groupedOptions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$labels[$value] = $groupedOptions[$value];
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
$labels[$value] = $options[$value] ?? $value;
|
||||
}
|
||||
|
||||
@@ -610,8 +631,8 @@ class Select extends Field implements Contracts\HasAffixActions, Contracts\HasNe
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string> $options
|
||||
* @return array<array{'label': string, 'value': string}>
|
||||
* @param array<string | array<string>> $options
|
||||
* @return array<array<string, mixed>>
|
||||
*/
|
||||
protected function transformOptionsForJs(array $options): array
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ use Illuminate\Support\Collection;
|
||||
trait HasOptions
|
||||
{
|
||||
/**
|
||||
* @var array<string> | Arrayable | class-string | Closure | null
|
||||
* @var array<string | array<string>> | Arrayable | class-string | Closure | null
|
||||
*/
|
||||
protected array | Arrayable | string | Closure | null $options = null;
|
||||
|
||||
@@ -21,7 +21,7 @@ trait HasOptions
|
||||
protected ?Closure $getSearchResultsUsing = null;
|
||||
|
||||
/**
|
||||
* @param array<string> | Arrayable | class-string | Closure | null $options
|
||||
* @param array<string | array<string>> | Arrayable | class-string | Closure | null $options
|
||||
*/
|
||||
public function options(array | Arrayable | string | Closure | null $options): static
|
||||
{
|
||||
@@ -31,7 +31,7 @@ trait HasOptions
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
* @return array<string | array<string>>
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user