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
Add the package styles in the <head>
using the helper @LivewireComboboxCss
:
<html>
<head>
@LivewireComboboxCss
</head>
<body>
...
</body>
</html>
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.
If you want to disabled the field while it is empty...
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 you want to remove it, you 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
{
protected 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
{
protected string $containerClass = '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 damian.aguilarm@gmail.com instead of using the issue tracker.
The MIT License (MIT). Please see License File for more information.