In this section, we have gathered various non-standard approaches to using Select
, which you can modernize for your needs.
Async
The example demonstrates the async
method, but at the same time, we use the approach of working through asyncMethod
, thus saving time on creating a controller and writing the implementation directly in the resource or page:
protected function formFields(): iterable
{
return [
Select::make('Select')->async(
$this->getAsyncMethodUrl('selectOptions'),
)->asyncOnInit(),
]
}
public function selectOptions(): MoonShineJsonResponse
{
$options = new Options([
new Option(label: 'Option 1', value: '1', selected: true, properties: new OptionProperty(image: 'https://cutcode.dev/images/platforms/youtube.png')),
new Option(label: 'Option 2', value: '2', properties: new OptionProperty(image: 'https://cutcode.dev/images/platforms/youtube.png')),
]);
return MoonShineJsonResponse::make(data: $options->toArray());
}
protected function formFields () : iterable
{
return [
Select :: make ( 'Select' ) -> async (
$this -> getAsyncMethodUrl ( 'selectOptions' ),
) -> asyncOnInit (),
]
}
public function selectOptions () : MoonShineJsonResponse
{
$options = new Options ([
new Option ( label : 'Option 1' , value : '1' , selected : true , properties : new OptionProperty ( image : 'https://cutcode.dev/images/platforms/youtube.png' )),
new Option ( label : 'Option 2' , value : '2' , properties : new OptionProperty ( image : 'https://cutcode.dev/images/platforms/youtube.png' )),
]);
return MoonShineJsonResponse :: make ( data : $options -> toArray ());
}
protected function formFields(): iterable
{
return [
Select::make('Select')->async(
$this->getAsyncMethodUrl('selectOptions'),
)->asyncOnInit(),
]
}
public function selectOptions(): MoonShineJsonResponse
{
$options = new Options([
new Option(label: 'Option 1', value: '1', selected: true, properties: new OptionProperty(image: 'https://cutcode.dev/images/platforms/youtube.png')),
new Option(label: 'Option 2', value: '2', properties: new OptionProperty(image: 'https://cutcode.dev/images/platforms/youtube.png')),
]);
return MoonShineJsonResponse::make(data: $options->toArray());
}
Reactive
Select::make('Company', 'company')->options([
1 => 'Laravel',
2 => 'CutCode',
3 => 'Symfony',
])->reactive(function (FieldsContract $fields, mixed $value, Select $ctx, array $values): FieldsContract {
$fields->findByColumn('dynamic_value')?->options((int) $value === 1 ? [
4 => 4,
] : [2 => 2]);
return $fields;
}),
Select::make('Dynamic value', 'dynamic_value')->options([4 => 4])->reactive(),
Select :: make ( 'Company' , 'company' ) -> options ([
1 => 'Laravel' ,
2 => 'CutCode' ,
3 => 'Symfony' ,
]) -> reactive ( function ( FieldsContract $fields, mixed $value, Select $ctx, array $values) : FieldsContract {
$fields -> findByColumn ( 'dynamic_value' ) ?-> options (( int ) $value === 1 ? [
4 => 4 ,
] : [ 2 => 2 ]);
return $fields;
}),
Select :: make ( 'Dynamic value' , 'dynamic_value' ) -> options ([ 4 => 4 ]) -> reactive (),
Select::make('Company', 'company')->options([
1 => 'Laravel',
2 => 'CutCode',
3 => 'Symfony',
])->reactive(function (FieldsContract $fields, mixed $value, Select $ctx, array $values): FieldsContract {
$fields->findByColumn('dynamic_value')?->options((int) $value === 1 ? [
4 => 4,
] : [2 => 2]);
return $fields;
}),
Select::make('Dynamic value', 'dynamic_value')->options([4 => 4])->reactive(),
ShowWhen
Due to the fact that by default ShowWhen
removes hidden elements from the DOM
, we can duplicate several Select
with different values and display them based on a condition.
We added setNameAttribute
to avoid conflict when saving the form.
Select::make('Company', 'company')->options([
1 => 'Laravel',
2 => 'CutCode',
3 => 'Symfony',
]),
Select::make('Dynamic value', 'dynamic_value')
->setNameAttribute('dynamic_value_1')
->showWhen('company', '1')
->options([1 => 1, 2 => 2,]),
Select::make('Dynamic value', 'dynamic_value')
->setNameAttribute('dynamic_value_2')
->showWhen('company', '2')
->options([3 => 3, 4 => 4,]),
Select :: make ( 'Company' , 'company' ) -> options ([
1 => 'Laravel' ,
2 => 'CutCode' ,
3 => 'Symfony' ,
]),
Select :: make ( 'Dynamic value' , 'dynamic_value' )
-> setNameAttribute ( 'dynamic_value_1' )
-> showWhen ( 'company' , '1' )
-> options ([ 1 => 1 , 2 => 2 ,]),
Select :: make ( 'Dynamic value' , 'dynamic_value' )
-> setNameAttribute ( 'dynamic_value_2' )
-> showWhen ( 'company' , '2' )
-> options ([ 3 => 3 , 4 => 4 ,]),
Select::make('Company', 'company')->options([
1 => 'Laravel',
2 => 'CutCode',
3 => 'Symfony',
]),
Select::make('Dynamic value', 'dynamic_value')
->setNameAttribute('dynamic_value_1')
->showWhen('company', '1')
->options([1 => 1, 2 => 2,]),
Select::make('Dynamic value', 'dynamic_value')
->setNameAttribute('dynamic_value_2')
->showWhen('company', '2')
->options([3 => 3, 4 => 4,]),
onChangeMethod
This approach allows you to send a request when the main Select
is changed and return the html
for the next Select
, displaying it in the block by selector:
public function selectValues(): MoonShineJsonResponse
{
$options = new Options([
new Option('Option 1', '1', false, new OptionProperty(image: 'https://cutcode.dev/images/platforms/youtube.png')),
new Option('Option 2', '2', true, new OptionProperty(image: 'https://cutcode.dev/images/platforms/youtube.png')),
]);
return MoonShineJsonResponse::make()
->html(
(string) Select::make('Next')->options($options)
);
}
protected function formFields(): iterable
{
return [
Select::make('Select')->options([
1 => 1,
2 => 2,
])->onChangeMethod('selectValues', selector: '.next-select'),
Div::make()->class('next-select'),
];
}
public function selectValues () : MoonShineJsonResponse
{
$options = new Options ([
new Option ( 'Option 1' , '1' , false , new OptionProperty ( image : 'https://cutcode.dev/images/platforms/youtube.png' )),
new Option ( 'Option 2' , '2' , true , new OptionProperty ( image : 'https://cutcode.dev/images/platforms/youtube.png' )),
]);
return MoonShineJsonResponse :: make ()
-> html (
( string ) Select :: make ( 'Next' ) -> options ($options)
);
}
protected function formFields () : iterable
{
return [
Select :: make ( 'Select' ) -> options ([
1 => 1 ,
2 => 2 ,
]) -> onChangeMethod ( 'selectValues' , selector : '.next-select' ),
Div :: make () -> class ( 'next-select' ),
];
}
public function selectValues(): MoonShineJsonResponse
{
$options = new Options([
new Option('Option 1', '1', false, new OptionProperty(image: 'https://cutcode.dev/images/platforms/youtube.png')),
new Option('Option 2', '2', true, new OptionProperty(image: 'https://cutcode.dev/images/platforms/youtube.png')),
]);
return MoonShineJsonResponse::make()
->html(
(string) Select::make('Next')->options($options)
);
}
protected function formFields(): iterable
{
return [
Select::make('Select')->options([
1 => 1,
2 => 2,
])->onChangeMethod('selectValues', selector: '.next-select'),
Div::make()->class('next-select'),
];
}
Fragments
Thanks to the fact that Fragment
sends form data along with the request, we can change the set of Select
elements upon reloading the fragment:
protected function formFields(): iterable
{
$selects = [];
$value = request()->integer('_data.first', 1);
if($value === 1) {
$selects[] = Select::make('Second')->options([
1 => 1,
2 => 2,
]);
}
if($value === 2) {
$selects[] = Select::make('Third')->options([
1 => 1,
2 => 2,
]);
}
return [
Fragment::make([
Select::make('First')->options([
1 => 1,
2 => 2,
])->setValue($value)->onChangeEvent(
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'selects')
),
...$selects,
])->name('selects'),
];
}
protected function formFields () : iterable
{
$selects = [];
$value = request () -> integer ( '_data.first' , 1 );
if ($value === 1 ) {
$selects[] = Select :: make ( 'Second' ) -> options ([
1 => 1 ,
2 => 2 ,
]);
}
if ($value === 2 ) {
$selects[] = Select :: make ( 'Third' ) -> options ([
1 => 1 ,
2 => 2 ,
]);
}
return [
Fragment :: make ([
Select :: make ( 'First' ) -> options ([
1 => 1 ,
2 => 2 ,
]) -> setValue ($value) -> onChangeEvent (
AlpineJs :: event ( JsEvent :: FRAGMENT_UPDATED , 'selects' )
),
... $selects,
]) -> name ( 'selects' ),
];
}
protected function formFields(): iterable
{
$selects = [];
$value = request()->integer('_data.first', 1);
if($value === 1) {
$selects[] = Select::make('Second')->options([
1 => 1,
2 => 2,
]);
}
if($value === 2) {
$selects[] = Select::make('Third')->options([
1 => 1,
2 => 2,
]);
}
return [
Fragment::make([
Select::make('First')->options([
1 => 1,
2 => 2,
])->setValue($value)->onChangeEvent(
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'selects')
),
...$selects,
])->name('selects'),
];
}