livewire / flux

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

1.0.10 - Placeholder still not showing when using listbox in modal using dynamic options. #430

Closed marchampson closed 1 month ago

marchampson commented 1 month ago

This is linked to #304 but I couldn't reopen:

Placeholder doesn't populate until you dropdown options, close modal and reopen.

I've updated to 1.0.10 but still experiencing the same issue. I have a very basic modal where the options are dynamically generated - normally I am pulling these in from the DB:

This is when you first launch the modal, I have pre-selected option: 2

Image

If you drop down, you can see 2 is highlighted:

Image

test-modal.blade.php:

<flux:modal name="test-modal" class="md:w-96 space-y-6">
    <div>
        <flux:heading size="lg">Test Modal</flux:heading>
    </div>
    {{ $industry }}
    <flux:select wire:model="industry" variant="listbox" placeholder="Choose industry..." searchable>
        <x-slot name="search">
            <flux:select.search placeholder="Search..."/>
        </x-slot>
       @foreach($industries as $key => $industry)
           <flux:option value="{{ $key }}">
               {{ $industry }}
           </flux:option>
         @endforeach
    </flux:select>
</flux:modal>

TestModal.php

<?php

namespace App\Livewire;

use Livewire\Attributes\On;
use Livewire\Component;

class TestModal extends Component
{
    public $industry = 2;
    public $industries = [];

    #[On('load-data')]
    public function loadData()
    {
        $this->industries = [
            '1' => 'Agriculture',
            '2' => 'Automotive',
            '3' => 'Banking',
        ];
    }

    public function render()
    {
        return view('livewire.test-modal');
    }
}

The button to launch is from a parent, the list view essentially and just shows the modal and fires the event:

public function showTestModal()
    {
        $this->dispatch('load-data')->to(\App\Livewire\TestModal::class);
        Flux::modal('test-modal')->show();
    }

I have a lot of these in my application, where there is a single modal on a parent list view and clicking on a row in a table, will launch the modal and run a method to load the data. All data loads, except for the placeholders.

Thanks.

jeffchown commented 1 month ago

@marchampson I have been able to recreate the issue you describe.

Do the select options change often? If they're mainly data-driven with infrequent changes, could you load them in the mount() method to workaround this issue?

The other thing you could do, and is a pattern I use often, is to change your public array $industries property to a Computed property, e.g.:

#[Computed]
public function industries(): array
{
    return [
        '1' => 'Agriculture',
        '2' => 'Automotive',
        '3' => 'Banking',
    ];
}

and, you can then delete the loadData() method and simplify the showTestModal() method to:

public function showTestModal()
{
    Flux::modal('test-modal')->show();
}

then in your view:

@foreach($this->industries as $key => $industry)

I tried this approach with your code and it works on my end.

Another reason I like this approach is because I keep all of my dynamic data code in one predictable place and can reference it easily in the component and view without any duplication (and get to benefit from Livewire's computed property caching to boot!)

marchampson commented 1 month ago

Hey @jeffchown thanks for looking into it.

In this instance, the values are dependant on the row you click, which opens the modal and populates the data. For example, a clients table. Click on the client, it opens the modal, loads the client data and this searchable dropdown is the client users so they can select an owner. I don't know the client until the row is clicked, so mount seems out of the equation.

I've tried the computed property route, when the 'load-data' event is picked up, in my actual component, it will set $this->client

#[On('load-client-data')]
    public function loadClientData($client_id)
    {
        if ($client_id) {
            $this->client = Team::find($client_id);
    ...

I then have a computed property:

 #[Computed]
    public function client_users()
    {
        return $this->client->users ?? [];
    }

Then I've swapped out the select to be:

<flux:select wire:model="defaultBoardsOwnerId" placeholder="Select user ..." variant="listbox" label="Default Board Owner" searchable>
                <x-slot name="search">
                    <flux:select.search placeholder="Search..."/>
                </x-slot>
                @foreach($this->client_users as $user)
                    <flux:option wire:key="board_user_{{ $user['id'] }}" value="{{ $user['id']}}">
                        {{ $user['name'] }}
                    </flux:option>
                @endforeach
            </flux:select>

Sadly, the same thing - no placeholder but the actual board owner is correctly ticked:

Image

However, if I could set the client in the mount(), I hardcoded to test, it does work as you say with the pattern above:

Image

But I'm not sure how I could do that if it's dynamically loading the client data?

jeffchown commented 1 month ago

@marchampson Ah, I see. Thanks for the extra context.

I have a similar pattern in one of my apps and use a very similar approach to the one you've shared here. Mine works as expected, but my flux:select does not use variant="listbox".

Do all other inputs in your modal work, except the flux:select with variant="listbox"?

marchampson commented 1 month ago

@jeffchown yes, if I convert to a basic select, it's fine.

However these lists can be rather long and I think once you have to scroll it's better to have a search. I used to use select2 but found there was so much code for those and you had to coax them along sometimes.

If this can be fixed then it's a game-changer for me. To be honest, Flux is already a game-changer, it's just this little niggle.

jeffchown commented 1 month ago

@marchampson Gotcha. I hear you re: select2 (and similar alternatives) and am hoping Flux will be able to replace a few similar js input libraries I've had to resort to in the past.

This discussion may have uncovered something I also have to account for in one of my apps.
Thanks for pointing this issue out and for the discussion.

Hopefully it will be a (relatively) easy for for @calebporzio and team.

marchampson commented 1 month ago

@jeffchown Thanks for taking the time to investigate and offer suggestions! Hopefully this sheds some light and as you say, @calebporzio and team can work their magic.

WorthLMS commented 1 month ago

Following: Placeholder doesn't appear to be working at all with variant="listbox" even without doing anything...

I have static options set, and a default option with "" and nothing is pre-selected when I load a Modal

marchampson commented 1 month ago

This is fixed for me in v1.0.14

Caleb just sent out a full list of all the fixed niggles that went into this release and this one fits the bill:

Show default selected value on lazy-loaded selects

Top work @calebporzio Thanks!

marchampson commented 1 month ago

I may have been a bit hasty to close this. I'm seeing mixed results. @jeffchown how about you?

jeffchown commented 1 month ago

@marchampson I haven't had any problems. But I'm curious to see if another issue's fix (https://github.com/livewire/flux/issues/453#issuecomment-2423060118) might fix this issue for some people.

marchampson commented 1 month ago

Thanks @jeffchown it still seems intermittent for me. Open a modal, the placeholder doesn't show, open a few more, nothing. Open the first one again, it shows and then from that moment, they all work.

calebporzio commented 1 month ago

Thanks for this report and to others for the help!

Can someone provide ideally a single copy/pastable volt component? and if not, clearer instructions/code to reproduce with?

marchampson commented 1 month ago

Sure, I had a simple test component when I posted. I’ll put another more copy/pastable one together.

Thanks

marchampson commented 1 month ago

OK, sorry @calebporzio this may be no help whatsoever. I've put the code from above into a Volt component, but haven't used Volt before. While the modal opens, the listbox doesn't. A standard select works, but hopefully you'll see what I've done wrong. Essentially though, I have a table view and a modal in a livewire component on the same view. When you click on a row, it should launch the modal and load in the data. The options do load, but it doesn't always load the placeholder, certainly not first time. If you click to another row and then back, it does:

<?php

use Flux\Flux;
use Livewire\Attributes\On;
use Livewire\Volt\Component;

new class extends Component {
    public $industry = 2;
    public $industries = [];

    public function showModal()
    {
        $this->dispatch('load-data')->self();
        Flux::modal('test-modal')->show();
    }

    #[On('load-data')]
    public function loadData()
    {
        $this->industries = [
            '1' => 'Agriculture',
            '2' => 'Automotive',
            '3' => 'Banking',
        ];
    }
}; ?>

<div xmlns:flux="http://www.w3.org/1999/html">
    <flux:button wire:click="showModal()">Test Modal</flux:button>

    <flux:modal name="test-modal" class="md:w-96 space-y-6 h-[300px]">
        <div>
            <flux:heading size="lg">Test</flux:heading>
        </div>
        <flux:select wire:model="industry" variant="listbox" placeholder="Choose industry..." searchable>
            <x-slot name="search">
                <flux:select.search placeholder="Search..."/>
            </x-slot>
            @foreach($industries as $key => $industry)
                <flux:option value="{{ $key }}">
                    {{ $industry }}
                </flux:option>
            @endforeach
        </flux:select>
    </flux:modal>
</div>

Thanks

jeffchown commented 1 month ago

@marchampson Don't you mean sometimes it does show the selected value? It does check the correct value in the select's dropdown, but doesn't show it properly in the field (on initial open).

marchampson commented 1 month ago

Hi @jeffchown, isn't that what I said ;) definitely what I meant, but thanks for confirming.

jeffchown commented 1 month ago

When I read 'Placeholder', I normally think of the value indicated by placeholder="Choose industry..." in your select. Thanks for confirming it is the selected value, @marchampson 👍

jeffchown commented 1 month ago

Based on your confirmation @marchampson , I believe this issue is the same as https://github.com/livewire/flux/issues/453 which @calebporzio has fixed and the fix will be part of the next release.

marchampson commented 1 month ago

I think you're absolutely right @jeffchown - it does appear to be the same as #453 - I'm on 1.0.14 so will wait for the next release and test again.

jeffchown commented 1 month ago

Tested w/ v.1.0.15 = fixed! Thanks, @calebporzio !

marchampson commented 1 month ago

I'll have to test this properly tomorrow but not fixed for me I'm afraid. Now I don't even have the tick on the selected item when you dropdown.

I don't have any flux views published, I've cleared app views and cache, definitely upgraded to 1.0.15.

I'll put together a simpler component in the morning but one that still loads data as the flyout modal is opened.

marchampson commented 1 month ago

Exactly the same code as before (top of this issue) but now I don't have the tick, excuse the extra large image :) :

Image

jeffchown commented 1 month ago

@marchampson Using your Volt code from above, it works for me with v1.0.16 (and when setting $industry to either 2 or '2' - I thought it might be an integer issue).

Have you deleted/republished any previously published Flux components, cleared the view cache, etc?

marchampson commented 1 month ago

Hey @jeffchown thanks for looking. I haven't published any Flux components and definitely cleared all views/cache.

Your integer idea was interesting though. I updated the fixed selected value in my test to be a string and now I get the tickbox:

Image

<?php

namespace App\Livewire;

use Livewire\Attributes\On;
use Livewire\Component;

class TestModal extends Component
{
    public $industry = '2';
    public $industries = [];

    #[On('load-data')]
    public function loadData()
    {
        $this->industries = [
            '1' => 'Agriculture',
            '2' => 'Automotive',
            '3' => 'Banking',
        ];
    }
    public function render()
    {
        return view('livewire.test-modal');
    }
}

But still not showing selected value when the dropdown loads:

Image

jeffchown commented 1 month ago

@marchampson You're welcome. Glad that seemed to get you a step closer, but I'm still stumped as to why it isn't working for you. Your Volt code works perfectly for me.

This problem sounds like one that may have been resolved a few versions back. Are you sure you are running Livewire v3.5.12 and Flux v1.0.16 and have done a fresh npm run build, etc.?

When you run composer show, this is what you see re: Livewire packages?:

Image

marchampson commented 1 month ago

OK, all good now! 1.0.16 must have come out while I was travelling home. The strangest thing, I'm sure when I looked yesterday livewire/flux-pro was on 1.0.15 but the upgrade just now said it went 1.0.4 -> 1.0.16.

All looks good now:

╰─ composer show | grep livewire
─╯
livewire/flux                                1.0.16           The official UI component library for Livewire.
livewire/flux-pro                            1.0.16           The pro version of Flux, the official UI component library for Livewire.
livewire/livewire                            3.5.12

All tests that failed no longer do and all looks good. @jeffchown really appreciate the extra help and testing on this one. @calebporzio thanks for fixing, even if I was a little late to the party :)

Will close this one now.

jeffchown commented 1 month ago

You're welcome @marchampson. Mystery solved 👍 Glad you got it working!

jeffchown commented 1 month ago

PS What you describe re the updating could be related to this https://github.com/livewire/flux/issues/492

marchampson commented 1 month ago

PS What you describe re the updating could be related to this #492

Looks to be exactly that, thought I was going mad! Top man @jeffchown

jeffchown commented 1 month ago

As did I initially, when I updated to 1.0.15.

Thanks, @marchampson - very UK of you 👍