daguilarm/livewire-combobox

A Livewire select combobox for Laravel

v1.3 2021-05-11 16:49 UTC

This package is auto-updated.

Last update: 2024-04-12 19:33:42 UTC


README

Package Logo

Latest Version on Packagist StyleCI GitHub last commit

Livewire Combobox: A dynamic selects for Laravel Livewire

A Laravel Livewire multiple selects depending on each other values, with infinite levels of dependency and totally configurable.

Requirements

This package need at least:

  • PHP ^8.0
  • Laravel ^8.0
  • Laravel Livewire ^2.0
  • TailwindCSS ^2.0

Installation

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>

Documentation

General Methods

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:

make()

The method make(), has the following structure:

Select::make(string $label, ?string $model = null);

model()

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.

uriKey()

This method is mandatory, it is used to define a unique key for the element.

hideOnEmpty()

Dependent children are removed if they are empty, instead of showing an empty field.

withoutResponse()

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.

Child elements

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:

dependOn()

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.

foreignKey()

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');

selectRows()

It is used to select the fields from the table that we want to load in the child element.

disabledOnEmpty()

If you want to disabled the field while it is empty...

Field Types

At the moment, the package support the folowing field types:

Select field

These fields have the following methods:

options()

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>

firstRemoved()

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().

Search field

comming soon...

Loading...

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.

Customize the display of elements

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)

Changelog

Please see CHANGELOG for more information what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email damian.aguilarm@gmail.com instead of using the issue tracker.

Credits

License

The MIT License (MIT). Please see License File for more information.