livewire / flux

The official Livewire UI component library
https://fluxui.dev
485 stars 42 forks source link

1.0.23 [HELP WANTED] searchable select -> open + focus on search by default #706

Closed lotje-kinable closed 1 day ago

lotje-kinable commented 2 days ago

Hi there! 👋

Can someone show me how to open a searchable select via Livewire (or alpine) with focus on the search field? I just don't have a clue where to start!

As I am directing my users to a modal where they can search in a select, I would save them an extra click, if the focus is set on the search field!

<flux:select variant="listbox" searchable placeholder="Choose industries...">
    <flux:option>Photography</flux:option>
    <flux:option>Design services</flux:option>
    <flux:option>Web development</flux:option>
    <flux:option>Accounting</flux:option>
    <flux:option>Legal services</flux:option>
    <flux:option>Consulting</flux:option>
    <flux:option>Other</flux:option>
</flux:select>

So

  1. user click button "select address"
  2. modal opens with searchable select
  3. search is open and focused

[ And I know I could save them a click, but all the address logic is contained in this modal, so duplication that code is almost impossible ]

Thanks in advance!!!!!!!

jeffchown commented 2 days ago

@lotje-kinable Have you tried variant="combobox" instead? Sounds like it might be a better match for your usecase. Or maybe even an autocomplete (https://fluxui.dev/components/autocomplete)

lotje-kinable commented 2 days ago

@jeffchown Honestly I don't really know where to start with the variant="combobox"!

What does autocomplete do? Is it available for a foreach? And can I hook into the search? Because searching for a client is not just straightforward searching for the name, it is a 'getClientString' either a person or company can be a client....

-> I am not lazy or anything, I am just a little lost at this point, and I think that autofocus on the search is not a strange thing, so maybe there is a solution, that gives me the option to just use the flux select with searchable, and I wanted to explore that first.

Thanks!

jeffchown commented 2 days ago

@lotje-kinable Here's an example (using Caleb's Sushi driver, https://github.com/calebporzio/sushi, to simulate a database):

app/Models/Industry.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Sushi\Sushi;

class Industry extends Model
{
    use Sushi;

    protected $rows = [
        ['id' => 1, 'name' => 'Design services'],
        ['id' => 2, 'name' => 'Photography'],
        ['id' => 3, 'name' => 'Web development'],
        ['id' => 4, 'name' => 'Accounting'],
        ['id' => 5, 'name' => 'Legal services'],
        ['id' => 6, 'name' => 'Consulting'],
        ['id' => 7, 'name' => 'Other'],
    ];
}

app/Livewire/CustomSearch.php

<?php

namespace App\Livewire;

use App\Models\Industry;
use Illuminate\Database\Eloquent\Collection;
use Livewire\Attributes\Computed;
use Livewire\Component;

class CustomSearch extends Component
{
    public string $search = '';

    #[Computed()]
    public function industries(): Collection
    {
        return Industry::query()
            ->where('name', 'LIKE', '%'.$this->search.'%')
            ->get();
    }

    public function render()
    {
        return view('livewire.custom-search');
    }
}

resources/views/livewire/custom-search.blade.php

<div>
    <flux:select variant="combobox" placeholder="Choose industry..." :filter="false" >
        <x-slot name="input">
            <flux:select.input wire:model.live="search" autofocus />
        </x-slot>

        @foreach ($this->industries as $industry)
            <flux:option wire:key="{{ $industry->id }}" value="{{ $industry->id }}">
                {{ $industry->name }}
            </flux:option>
        @endforeach
    </flux:select>
</div>
lotje-kinable commented 1 day ago

@jeffchown Thank you! Never used Sushi before, I installed it!

I am going to give it a try!!

Thanks again, and for all the other help too, you're amazing!!

lotje-kinable commented 1 day ago

@jeffchown

When I put the select with autofocus, in a modal, the autofocus works

But, when I import the modal from a differrent page, the autofocus does not work!

Eg. a company has an industry, when creating a new company an industry can be selected from a flux:modal located in modals.flux-modal.blade.php, then the autofocus does not trigger/update

lotje-kinable commented 1 day ago

@jeffchown

I will use alpine for the autofocus, when I call the modal from a different view.

This code should be in a flux:modal called from a different blade view:

<div x-data x-init="$nextTick(() => $refs.autoFocus.focus())>
    <flux:select variant="combobox" placeholder="Choose industry..." :filter="false" >
        <x-slot name="input">
            <flux:select.input wire:model.live="search" x-ref="autoFocus" />
        </x-slot>

        @foreach ($this->industries as $industry)
            <flux:option wire:key="{{ $industry->id }}" value="{{ $industry->id }}">
                {{ $industry->name }}
            </flux:option>
        @endforeach
    </flux:select>
</div>

I think that is the easiest and solution.

Thanks again Jeff, honestly, for taking the time to write out all the code, really, it would have taken me such a long time, if you did not give me a start!!! 🥳

jeffchown commented 1 day ago

You're welcome @lotje-kinable ! Autofocus can be tricky, especially in modals. I've used a solution like the one you posted above as well.