Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1.0.23] flux.js error: Uncaught TypeError: Cannot redefine property: disabled #708

Open
lotje-kinable opened this issue Nov 21, 2024 · 13 comments

Comments

@lotje-kinable
Copy link

Hi 👋

I have

  • checkbox/radio to change the items in the foreach

  • a foreach in a flux:table

  • with a trigger - modal (with :name="name-$option->id" as instructed)

  • that contains a flux:select ( with wire:key="select-choice-{{$choice->id}}" set)

  • a screencast

  • a Volt component (sorry about the code, I need all of it, to recreate the issue I am having on my production project)

The Issue:
On my actual project, the data does not load when changing the value of the radio or checkbox, when the SELECT inside the modal is commented out, the error dissapears and all works as expected.

I don't think that having a flux:select inside a modal is prohibited or weird. I hope it will work because it is superfast!

The error:
Cannot redifine property: disabled

flux.js?id=5b5b9c60:2262 Uncaught TypeError: Cannot redefine property: disabled
at Function.defineProperty ()
at Disableable.boot (flux.js?id=5b5b9c60:2262:14)
at new Mixin (flux.js?id=5b5b9c60:1799:18)
at new Disableable (flux.js?id=5b5b9c60:2259:21)
at HTMLElement.mount (flux.js?id=5b5b9c60:4745:27)
at flux.js?id=5b5b9c60:1745:21

cannot.redefine.disabled.mov
<?php
use Livewire\Volt\Component;
use Livewire\Attributes\Computed;

new

class extends Component {


    public $choices;
    public $choiceId;

    public $radioOptions = "all";

    public function mount()
    {
        $this->choices = collect([
            (object)['id' => 1, 'name' => 'a'],
            (object)['id' => 2, 'name' => 'b'],
            (object)['id' => 3, 'name' => 'c'],

        ]);
    }

    #[Computed]
    public function options()
    {
        $items = collect([
            (object)['id' => 1, 'name' => 'foo', 'toggleOptions' => 'true', 'choiceId' => null],
            (object)['id' => 2, 'name' => 'bar', 'toggleOptions' => 'false', 'choiceId' => null],
            (object)['id' => 3, 'name' => 'baz', 'toggleOptions' => 'true', 'choiceId' => null],
            (object)['id' => 4, 'name' => 'qux', 'toggleOptions' => 'false', 'choiceId' => null],
            (object)['id' => 5, 'name' => 'quux','toggleOptions' => 'true', 'choiceId' => null],
        ]);

        if ($this->radioOptions !== 'all') {
            return $items->filter(fn($item) => $item->toggleOptions === $this->radioOptions);
        }

        return $items;
    }

    public function saveChoice($optionId)
    {
        $this->options->where('id', $optionId)->first()->choiceId = $this->choiceId;
        $this->choiceId = null;
    }

}; ?>

<div class="space-y-28">

    <div>

        <flux:radio.group wire:model.change="radioOptions" label="Select your options">
            <flux:radio value="all" label="All options" />
            <flux:radio value="true" label="True options" />
            <flux:radio value="false" label="False options" />
        </flux:radio.group>

        <flux:table>
            <flux:columns>
                <flux:column>Id</flux:column>
                <flux:column>Name</flux:column>
                <flux:column>Choice</flux:column>

            </flux:columns>

            <flux:rows>
                @foreach($this->options as $option)
                    <flux:row wire:key="option-{{ $option->id }}">
                        <flux:cell>{{ $option->id }}</flux:cell>
                        <flux:cell>{{ $option->name }}</flux:cell>
                        <flux:cell>

                            @if($option->choiceId)
                                {{ $option->choiceId }}
                            @else
                                <flux:modal.trigger :name="'choice-option'.$option->id">
                                    <flux:button size="sm">
                                        {{  $taxi->driver?->name ?? 'Kies bestuurder' }}
                                    </flux:button>
                                </flux:modal.trigger>



                                <flux:modal :name="'choice-option'.$option->id" class="space-y-6 md:w-96">
                                    <div>
                                        <flux:heading size="lg">Choose</flux:heading>
                                    </div>



                                    <div class="space-y-3">
                                        <flux:field>

                                            {{-- When the select is commented out, the error dissapears --}}

                                            <flux:select wire:model.live='choiceId' variant="listbox" placeholder='Select option' >
                                                @foreach($choices as $choice)
                                                    <flux:option wire:key="choice-{{ $choice->id }}" value="{{ $choice->id }}">{{ $choice->name }}</flux:option>
                                                @endforeach
                                            </flux:select>

                                            <flux:error name="choiceId" />
                                        </flux:field>
                                    </div>


                                    <div class="the-card-buttons">
                                        <flux:spacer />
                                        <flux:button wire:click="saveChoice({{ $option->id }})" variant="primary">Save</flux:button>
                                        <flux:modal.close>
                                            <flux:button variant="ghost">Cancel</flux:button>
                                        </flux:modal.close>
                                    </div>
                                </flux:modal>
                            @endif
                        </flux:cell>
                    </flux:row>
                @endforeach

            </flux:rows>
        </flux:table>

    </div>


</div>

It is hard to explain, so I hope I've provided enough information!

Thanks in advance!

@jeffchown
Copy link

jeffchown commented Nov 21, 2024

@lotje-kinable I believe the issue is the flux:modal code being in the flux:cell.
When you wrap the flux:modal in @teleport to 'teleport' the code to the end of the body element, it works for me.

e.g. change your flux:model to:

@teleport('body')
    <flux:modal :name="'choice-option'.$option->id" class="space-y-6 md:w-96">
        <div>
            <flux:heading size="lg">Choose</flux:heading>
        </div>

        <div class="space-y-3">
            <flux:field>

                {{-- When the select is commented out, the error dissapears --}}

                <flux:select wire:model.live='choiceId' variant="listbox" placeholder='Select option' >
                    @foreach($choices as $choice)
                        <flux:option wire:key="choice-{{ $choice['id'] }}" value="{{ $choice['id'] }}">{{ $choice['name'] }}</flux:option>
                    @endforeach
                </flux:select>

                <flux:error name="choiceId" />
            </flux:field>
        </div>

        <div class="the-card-buttons">
            <flux:spacer />
            <flux:button wire:click="saveChoice({{ $option->id }})" variant="primary">Save</flux:button>
            <flux:modal.close>
                <flux:button variant="ghost">Cancel</flux:button>
            </flux:modal.close>
        </div>
    </flux:modal>
@endteleport

When using flux:modals, I try to make sure my flux:modal elements are always at or near the </body> to avoid any unexpected side-effects of nesting in other elements. @teleport makes that easy!

@tm-blg
Copy link

tm-blg commented Nov 21, 2024

Hello! You are trying to define modals inside a loop. And you are also trying to dynamically change the variable ;; on which the output of modal windows depends, which leads to the same error... Conclusion, modals must be defined separately.

Somewhere in a parallel universe, the correct code would be like this:

#[Validate('required')]
    public $choiceId;

    public $options, $radioOptions = "all", $choices = [1,2,3];

    public function mount()
    {
        $this->options = collect([
            (object)['id' => 1, 'name' => 'foo', 'toggleOptions' => 'true', 'choiceId' => null],
            (object)['id' => 2, 'name' => 'bar', 'toggleOptions' => 'false', 'choiceId' => null],
            (object)['id' => 3, 'name' => 'baz', 'toggleOptions' => 'true', 'choiceId' => null],
            (object)['id' => 4, 'name' => 'qux', 'toggleOptions' => 'false', 'choiceId' => null],
            (object)['id' => 5, 'name' => 'quux', 'toggleOptions' => 'true', 'choiceId' => null],
        ]);
    }

    public function saveChoice($optionId)
    {
        $this->validateOnly('choiceId');
        $this->options->where('id', $optionId)->first()->choiceId = $this->choiceId;
        $this->choiceId = null;
        $this->modal('choice-option'.$optionId)->close();
    }`


    <flux:radio.group wire:model.change="radioOptions" label="Select your options">
        <flux:radio value="all" label="All options"/>
        <flux:radio value="true" label="True options"/>
        <flux:radio value="false" label="False options"/>
    </flux:radio.group>
    <flux:table>
        <flux:columns>
            <flux:column>Id</flux:column>
            <flux:column>Name</flux:column>
            <flux:column>Choice</flux:column>
        </flux:columns>
        <flux:rows>
            @foreach(($radioOptions <> 'all' ? $this->options->where('toggleOptions', $radioOptions) : $this->options) as $option)
                <flux:row wire:key="option-{{ $option->id }}">
                    <flux:cell>{{ $option->id }}</flux:cell>
                    <flux:cell>{{ $option->name }}</flux:cell>
                    <flux:cell>
                        @if($option->choiceId)
                            {{ $option->choiceId }}
                        @else
                            <flux:modal.trigger :name="'choice-option'.$option->id">
                                <flux:button size="sm">Kies bestuurder</flux:button>
                            </flux:modal.trigger>
                        @endif
                    </flux:cell>
                </flux:row>
            @endforeach
        </flux:rows>
    </flux:table>
    @foreach($this->options as $option)
        <flux:modal :name="'choice-option'.$option->id" class="space-y-6 md:w-96">
            <flux:heading size="lg">Choose</flux:heading>
            <flux:select wire:model.change='choiceId' variant="listbox" placeholder='Select option'>
                @foreach($choices as $key)
                    <flux:option>{{ $key }}</flux:option>
                @endforeach
            </flux:select>
            <flux:spacer/>
            <flux:button wire:click="saveChoice({{ $option->id }})" variant="primary">Save</flux:button>
            <flux:modal.close>
                <flux:button variant="ghost">Cancel</flux:button>
            </flux:modal.close>
            <flux:error name="choiceId"/>
        </flux:modal>
    @endforeach

@lotje-kinable
Copy link
Author

@jeffchown actually the flux:modal works fine, but it is the flux:select with the @foreach inside the fllux:modal that seems to throw the error.

-> I tried the @teleport('body') and now I get a few "to.setAttribute is not a function" errors.

module.cjs.js:354 Uncaught TypeError: to.setAttribute is not a function
at seedingMatchingId (module.cjs.js:354:6)
at patchChildren (module.cjs.js:120:7)
at patchChildren (module.cjs.js:173:9)
at patch (module.cjs.js:68:5)
at patchChildren (module.cjs.js:220:7)
at patch (module.cjs.js:68:5)
at patchChildren (module.cjs.js:220:7)
at patch (module.cjs.js:68:5)
at patchChildren (module.cjs.js:220:7)
at patch (module.cjs.js:68:5)

@jeffchown
Copy link

jeffchown commented Nov 21, 2024

@lotje-kinable I tested your Volt component after wrapping the flux:modal with @teleport...@endteleport and everything worked for me with no console errors when using the modal multiple times, changing the radioOptions, changing the select in the modal.

Did you php artisan view:clear and npm run build after making the @teleport change?

If so, then maybe you'll need to give @tm-blg 's suggestion a try.

@lotje-kinable
Copy link
Author

@jeffchown It works!

I did not run 'php artisan view:clear' (but npm run dev was running).

Could you tell my why 'php artisan view:clear' is necessary?

Thanks again!

@jeffchown
Copy link

jeffchown commented Nov 21, 2024

@lotje-kinable Great! You're welcome :)

Blade views are compiled to optimize performance, when developing, after editing blade files, it is a good idea to run php artisan view:clear to make sure your browser isn't loading an 'old' (previously compiled) version of the view you are working on/testing.

The Laravel doc is here https://laravel.com/docs/11.x/views#optimizing-views

@lotje-kinable
Copy link
Author

@jeffchown
a follow up question: can I use 2 @teleport('body') on the same blade view?

I thought they always recompile when using vite! thanks for the tip!

@jeffchown
Copy link

@lotje-kinable Vite does refresh 'normal' Blade file changes when running npm run dev and with your vite.config.js file's, refresh: true (see https://laravel.com/docs/11.x/vite#blade-refreshing-on-save), but I find that when I make changes to my Livewire view files, they sometimes do not refresh/reload properly (especially after adding something like @teleport).

So, if something doesn't work as I expect after an edit, I run php artisan view:clear to be sure I'm working with the most current changes.

As for 2 @teleport('body')s in one file... I've never tried it, but in theory it should work.
That said, I find if I'm reaching for @teleport too often, it usually means I should restructure my code.

@lotje-kinable
Copy link
Author

@jeffchown I'll keep it in mind, thanks for the explanations!

Maybe I am doing something wrong with the flux:select tbh, I worked with the teleport and now I have put the flux:modal outside of the table, and open/close it with livewire (which is slower). But the error:

module.cjs.js:354 Uncaught TypeError: to.setAttribute is not a function
at seedingMatchingId (module.cjs.js:354:6)
at patchChildren (module.cjs.js:120:7)
at patchChildren (module.cjs.js:173:9)
at patch (module.cjs.js:68:5)
at patchChildren (module.cjs.js:220:7)
at patch (module.cjs.js:68:5)
at patchChildren (module.cjs.js:220:7)
at patch (module.cjs.js:68:5)
at patchChildren (module.cjs.js:220:7)
at patch (module.cjs.js:68:5)

keeps popping up when I uncomment the foreach section of the flux:select! The options in the foreach are bound to a computed property and when I toggle the radio, it pops up. But when I comment the flux:select in either of the solutions, the error goes away!

@jeffchown
Copy link

@lotje-kinable You're welcome.

At this point, I can't recreate the error (your code with the select uncommented works for me - with @teleport), so unfortunately, I'm unable to help.

@lotje-kinable
Copy link
Author

lotje-kinable commented Nov 21, 2024

@jeffchown It seems to work, with the error in the console, so maybe it is something internal.

Just curious: Can you see the error in you console?

I wrapped the flux:modal with wire:model.self="showModal" in an @if($showModal) and the error is gone! Maybe it was trying to load the flux:select values when the page loaded or something...

@jeffchown
Copy link

@lotje-kinable Sounds like you are working with different code than the example you provided as there is no wire:model.self="showModal" in the Volt component.

No errors in my console when using your example, with the changes we've been discussing.

@lotje-kinable
Copy link
Author

@jeffchown well, yes, instead of using teleport, I put the modal outside of the flux:table, and open it with livewire. Since I still got the errors with teleport after running the command, I thought I would try something else.

Thanks for confirming. I still get the errors with teleport, in my Volt component. (after view:clear + npm run build)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants