A Laravel Livewire multiple selects depending on each other values, with infinite levels of dependency and totally configurable.
This package need at least:
- PHP ^8.0
- Laravel ^8.0
- Laravel Livewire ^2.0
- TailwindCSS ^2.0
You can install the package via composer:
composer require daguilarm/livewire-combobox
The first thing you have to do is create a component in your folder Livewire. Below you can see an example using three selects:
<?php
declare(strict_types=1);
namespace App\Http\Livewire;
use App\Models\Car;
use App\Models\Extra;
use App\Models\Option;
use Daguilarm\LivewireCombobox\Components\ComboboxLivewireComponent;
use Daguilarm\LivewireCombobox\Components\Fields\Select;
use Daguilarm\LivewireCombobox\Contracts\Combobox;
class ComboboxCars extends ComboboxLivewireComponent implements Combobox
{
public function elements(): array
{
return [
Select::make('Cars', Car::class)
->uriKey('key-for-car')
->options(function($model) {
return $model
->pluck('name', 'id')
->toArray();
}),
Select::make('Options for cars', Option::class)
->uriKey('key-for-options')
->dependOn('key-for-car')
->foreignKey('car_id')
->selectRows('id', 'option'),
Select::make('Extras for cars')
->model(Extra::class)
->firstRemoved()
->hideOnEmpty()
->uriKey('key-for-extras')
->dependOn('key-for-options')
->foreignKey('option_id')
->selectRows('id', 'extra')
->withoutResponse(),
];
}
}
The package supports infinite dependent elements. The method elements()
should return an array with all the elements.
Let's see how the class works Select::class
and its methods:
The method make()
, has the following structure:
Select::make(string $label, ?string $model = null);
As it can be seen, the attribute $model
is optional in the make()
method, and it can be added using the method model()
:
Select::make('My label')->model(User::class);
⚠️ Defining the model is mandatory, but it can be done in the two ways described.
This method is mandatory, it is used to define a unique key for the element.
Dependent children are removed if they are empty, instead of showing an empty field.
When we want an element does not send a response to the component and works only as a form field, that is, remove all the Laravel Livewire code from it. Very useful when it comes to the last selectable element and we don't want to send a request to the server.
These elements have their own methods, apart from those described above.
These child elements do not need the method options()
, although it can be added if desired. The child specific methods are described below:
With this method we define the parent element on which our child element depends. We must use the uriKey
from the parent element. The basic structure of the method is:
dependOn(?string $parentUriKey = null, ?string $foreignKey = null)
As can be seen, it admits a second value which is the foreing key that links the two models: Parent and Child.
This second field can also be added in two ways:
// Option 1
Select::make(...)
->dependOn('key-for-options', 'option_id');
// Option 2
Select::make(...)
->dependOn('key-for-options')
->foreignKey('option_id');
It is used to select the fields from the table that we want to load in the child element.
At the moment, the package support the folowing field types:
These fields have the following methods:
It is used to add the values that will be shown in the element select. We can directly add an array
with the values, or define a callback
. The two values returned by the array
: key and value, are shown as follows in the Blade template:
// The array
[
1 => 'Car',
2 => 'Bike',
3 => 'Plane'
]
//Will be render as
<option value="1">Car</option>
<option value="2">Bike</option>
<option value="3">Plane</option>
Therefore, in the component example (will be reverse):
// The array
Select::make(...)
->options(function($model) {
return $model
->pluck('name', 'id')
->toArray();
})
//Will be render as
<option value="id">name</option>
By default, each item will show a select field with an empty option
element:
// Element
<select>
<option value=""></option>
...
</select>
If we want to remove it, we can add the method firstRemoved()
.
comming soon...
You can activate or deactivate the loading state, modifying the attribute $loading
, in your component:
<?php
declare(strict_types=1);
namespace App\Http\Livewire;
use App\Models\Car;
use App\Models\Extra;
use App\Models\Option;
use Daguilarm\LivewireCombobox\Components\ComboboxLivewireComponent;
use Daguilarm\LivewireCombobox\Components\Fields\Select;
use Daguilarm\LivewireCombobox\Contracts\Combobox;
class ComboboxCars extends ComboboxLivewireComponent implements Combobox
{
public bool $loading = false;
public function elements(): array
{
return [];
}
}
By default it is activated (true). The template file is located at: resources/views/vendor/livewire-combobox/loading.blade.php
.
The package uses TailwindCSS so the styles must be based on it. The structure of the elements is as follows:
<!-- Main container -->
<div id="container">
<!-- Element 1 -->
<div id="element-container-1">
<label id="label-1"></label>
<select id="select-1"></select>
</div>
<!-- Element 2 -->
<div id="element-container-2">
<label id="label-2"></label>
<select id="select-2"></select>
</div>
</div>
We can modify the styles of the Main Container from the component that we created at the beginning of the documentation, using the $comboboxContainerClass
:
<?php
declare(strict_types=1);
namespace App\Http\Livewire;
use App\Models\Car;
use App\Models\Extra;
use App\Models\Option;
use Daguilarm\LivewireCombobox\Components\ComboboxLivewireComponent;
use Daguilarm\LivewireCombobox\Components\Fields\Select;
use Daguilarm\LivewireCombobox\Contracts\Combobox;
class ComboboxCars extends ComboboxLivewireComponent implements Combobox
{
public string $comboboxContainerClass = 'flex p-2 m-2 bg-gray-100';
public function elements(): array
{
return [];
}
}
To modify an element, we will have to do it directly from each of them, using the method class()
:
Select::make('Cars', Car::class)
->uriKey('key-for-car')
->options(function($model) {
return $model
->pluck('id', 'name')
->toArray();
})
->class('p-4', 'text-green-600', 'text-lg'),
We can use the new functionality of php 8 to modify only those parts that interest us, or we can use the method directly:
// Method 1
Select::make(...)
->class(
container: 'p-4',
field: 'text-lg',
),
// Method 2
Select::make(...)
->class('p-4', null, 'text-lg'),
The order of the parameters is:
class(?string $container = null, ?string $label = null, ?string $field = null)
Please see CHANGELOG for more information what has changed recently.
Please see CONTRIBUTING for details.
If you discover any security related issues, please email [email protected] instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.