livewire / flux

The official Livewire UI component library
406 stars 36 forks source link

Select not working inside a flyout modal #334

Open crisoberillo opened 3 days ago

crisoberillo commented 3 days ago

When using a flux:select inside a modal of variant flyout, I get a select that doesn't display any options (only the placeholder, if present). If I remove the variant="flyout" part and leave everything else like it is, it works as intended. The select with variant="listbox" seems to work with wire:model and shows the options, but doesn't initialize to the correct value.

Here is minimal snippet. If pasted inside a random blade file, it should reproduce the issue.

    <flux:modal.trigger name="test">
        <flux:button icon="plus">
            Open test
        </flux:button>
    </flux:modal.trigger>

    <flux:modal name="test" variant="flyout" class="space-y-6">
        <div>
            <flux:heading size="lg">That's a test</flux:heading>
            <flux:subheading>Check if the select input doesn't show elements.</flux:subheading>
        </div>

        <flux:input label="Test input field" placeholder="Insert your text here..." />

        <flux:field>
            <flux:label>Test select field</flux:label>
            <flux:select>
                <flux:option value="1">Easy</flux:option>
                <flux:option value="2">Medium</flux:option>
                <flux:option value="3">Hard</flux:option>
            </flux:select>
        </flux:field>

        <div class="flex">
            <flux:spacer />

            <flux:button type="submit" variant="primary">Save changes</flux:button>
        </div>
    </flux:modal>
jeffchown commented 3 days ago

@crisoberillo I just pasted your above code into a test blade belonging to a test Livewire component (and wrapped your code in a

) and all worked OK for me.

Image

crisoberillo commented 3 days ago

@jeffchown Thank you for your reply! I realize I had version 1.0.4. Now I updated to version 1.0.8 and it works for me only with listbox variant of the select. The normal select still gives me the issue (tested with firefox and chrome)

Image

Is there something I can post here to help identify the issue?

jeffchown commented 3 days ago

You're welcome, @crisoberillo .

One thing I forget sometimes when updating Flux to the latest version is to delete and republish any Flux components I may have previously published using php artisan flux:publish as some of the Flux blade files may have changed.

Did you publish any with 1.0.4?

crisoberillo commented 3 days ago

Nice suggestion, but I didn't publish anything :(

jeffchown commented 3 days ago

Hmmm... are you able to share an example app via a Github repo?

jeffchown commented 3 days ago

Not sure if this will help you, but here is a cleanwelcome.blade.php file (from a clean Laravel app install w/ Flux 1.0.8) I used to test your code:

The x-data in the wrapping div is needed to 'activate' the Alpine-related code as there is no other Livewire/Alpine on the page.

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Laravel</title>

        <!-- Styles -->
        @vite(['resources/css/app.css', 'resources/js/app.js'])

        @fluxStyles
    </head>

    <body class="font-sans antialiased bg-gray-100 dark:!bg-zinc-600">
        <div x-data>
            <flux:modal.trigger name="test">
                <flux:button icon="plus">
                    Open test
                </flux:button>
            </flux:modal.trigger>

            <flux:modal name="test" variant="flyout" class="space-y-6">
                <div>
                    <flux:heading size="lg">That's a test</flux:heading>
                    <flux:subheading>Check if the select input doesn't show elements.</flux:subheading>
                </div>

                <flux:input label="Test input field" placeholder="Insert your text here..." />

                <flux:field>
                    <flux:label>Test select field</flux:label>
                    <flux:select>
                        <flux:option value="1">Easy</flux:option>
                        <flux:option value="2">Medium</flux:option>
                        <flux:option value="3">Hard</flux:option>
                    </flux:select>
                </flux:field>

                <div class="flex">
                    <flux:spacer />

                    <flux:button type="submit" variant="primary">Save changes</flux:button>
                </div>
            </flux:modal>
        </div>

        @fluxScripts
    </body>
</html>
crisoberillo commented 3 days ago

Unfortunately I can't share an example app right now, but I will try later.

Meanwhile I tested your welcome view and the result was the same.

I want to say thank you for your effort!

jeffchown commented 3 days ago

Very strange that my welcome view didn't work for you. It must be something in the configuration of your app and/or a conflict with some other code or installed package.

You're welcome. Too bad we couldn't figure it out right now.

ThomasEnssner commented 2 days ago

I added a PR to add the option to 'force' overwrites to the flux:publish Command

mikecchops commented 2 days ago

I am facing this same issue. Selects work in modals, but not if variant="flyout".

Using latest version of Flux. No components published.

marchampson commented 2 days ago

I have a similar issue. My modal form is child component. If I load this directly into the view, the selects work. If I add it to a modal, normal or flyout, they don't show the selected value as the placeholder. If you open them up the correct value is ticked. I have latest version of Flux, php artisan flux:publish, just skips as they already exist.

Not sure if this has anything to do with it, but when the modal loads, I see this in the console, everything looks ok (except for the selects):

[Violation] Forced reflow while executing JavaScript took 31ms

mikecchops commented 2 days ago

Clearing views fixed it for me: php artisan view:clear

marchampson commented 2 days ago

Clearing views fixed it for me: php artisan view:clear

Sadly not for me. Cleared views, cache, rebuilt assets, re-run vite, tried the lot. Thanks for the suggestion though. Good to hear yours is sorted.

marchampson commented 2 days ago

OK, looks to be a timing issue. The modal is on a parent component and when you click on a child, it opens the modal on the parent and loads the data. Because I don't initially have the data, I've wrapped the form component in an if as below:

<flux:modal
        x-data
        x-on:open="$nextTick(() => { $refs.card-form-modal.scrollTo(0, 0); })"
        x-ref="card-form-modal"
        name="edit-card"
        variant="flyout"
        class="space-y-6 w-full max-w-5xl"
        @on.close="document.activeElement.blur(); $wire.closeModal()"
    >
        <div class="w-full">
            <flux:heading size="lg" class="mt-6">{{ $card->title ?? '' }}</flux:heading>
        </div>
        @php $card = Card::find(3); @endphp
        @if($card)
            <livewire:kanban.card-form :card_id="$card->id" :group_id="$card->group_id"
                                       wire:key="card-form-{{ $card->id }}"/>
        @endif
        <div class="flex">
...

I've forced the card so that it's there when the parent loads and everything is fine. So I'll have to rethink this one.

jeffchown commented 1 day ago

@marchampson It looks like your example is more complex than the initial issue posted.

Are you trying to reuse one modal, with a form inside it, to provide editing/updating for a chosen model from a table row?

If so, I usually use the following pattern:

public function findAndOpen(int $cardId): void { $card = Card::findOrFail($cardId);

$this->name = $card->name;
$this->groupId = $card->group_id;

$this->modal('edit-card-modal')->show();

}


I can then open this modal from any row in the related table by adding a link/button to each row something like this:

@foreach ($cards as $card)

... ... Edit @endforeach ``` If I'm way off re: your issue/needs, ignore this :) If not, hope it helps.
marchampson commented 1 day ago

Thanks @jeffchown you're spot on with regards to what I'm doing. Although, I am complicating it further still by using locking field components so anyone can view the card, but only one person can edit a field at any one time. Why have a simple form when you can completely over-engineer ;)

I'll try your suggestion. I have just managed to get it working after sleeping on the issue. When the data is reloaded for the flux:select, I fire an event that I listen for in the view and then remove and reinsert the select to the DOM. This fixes it, but feels like a hack, although I used to have to do a similar thing to re-initialise select2 components.

Thanks again for your help.

jeffchown commented 1 day ago

You're welcome, @marchampson.

Re: 'locking the field components', I also use 1 form for both display and edit based on the user's access level. In my case I find wrapping the entire form in a <fieldset> with a condition on the disabled makes it easy for me to enable/disable all of the form's inputs at once based upon a condition. e.g. <fieldset @disabled(auth()->user()->cannot('update', $client))>

marchampson commented 1 day ago

That's another great idea @jeffchown.

I took a slightly different approach, I've created a drag and drop form builder and use the same components in my kanban cards. When you click into the field it locks it and sends an event to lock everyone else out telling them who has it locked. Reverb has made this nice and quick:

<flux:input wire:model.defer="value"
                label="{{ ucwords(str_replace('_',' ',$name)) }}"
                type="text"
                badge="Required"
                class="disabled:border-yellow-500"
                wire:focus="lock()"
                wire:blur="unlock()"
                :disabled="$isLocked && ($isLocked->user->id !== auth()->id()) ? 'disabled' : null"
    />

Anyway, I went off my hack earlier as despite appearing to work, it's throwing an error in the console. So, I'm looking at your pattern now.

jeffchown commented 1 day ago

Thanks, @marchampson

Interesting idea re: the locking... what do you do to prevent someone walking away before submitting their form thus locking that card indefinitely? Have you implemented some type of timeout?

Hope my pattern helps with the other.

marchampson commented 1 day ago

Hey @jeffchown, I really want to say that I have implemented a timeout, but in fairness, I have just added that to my todo list. Thanks again!!

jeffchown commented 1 day ago

Love the candor, @marchampson ! You're welcome.

marchampson commented 1 day ago

Well, fwiw, I have tried many different routes and tbh, even if I preload the select, if it is variant="listbox", when the data is loaded into the modal, it will not refresh and show the selected item.

I saw a fix in the last release v1.0.8: Ensure that all selectable values are strings (not integers) - but I set my options as integers because they are calling from a database.

Sure I've missed something, but for now, the easy option is to output the selected value in the placeholder, e.g.:

placeholder="{{ $clients->firstWhere('clientCode', $clientCode)['clientName'] ?? 'Choose client...' }}"

Not overly happy with that, but there we are, it seems to work.

kyledoesdev commented 17 hours ago

I am facing this same issue. Selects work in modals, but not if variant="flyout".

Using latest version of Flux. No components published.

Same here for me. :/ Hoping he can get to this one soon!