valentin_vranic's avatar

Livewire 3 custom scripts not loaded in @script

For any particular reason the functions inside of my @script and @endscipt tag are not loaded.

What I want to achieve is that I have a select, where I want to initialize select2 with x-init.

<div class="row" wire:ignore
     x-init="select2Init"
>
    <div class="align-items-center">
        <select
            id="mp"
            class="mp"
            wire:model="form.mPortal"
            x-ref="selectMPortals"
            multiple
        >
            @foreach($mPortals as $mp)
                <option>
                    {{ $mp }}
                </option>
            @endforeach
        </select>
    </div>
</div>

And below:

@script
<script>
    function select2Init() {
        const select2 = $(this.$refs.selectMPortals).select2({
            dropdownParent: $('#siptrunk-form'),
            language: '{{ $lang }}',
            width: '100%',
            placeholder: '{{ __('messages.Selected numbers') }}',
        });

        select2.on('change', function (e) {
            let selectedOptions = $(this).select2('data');

            let selectedTexts = selectedOptions.map(option => option.text);

            @this.
            set('form.mPortals', selectedTexts);
        });
    }
</script>
@endscript

And on component load I'm getting an error

Uncaught ReferenceError: select2Init is not defined
0 likes
1 reply
LaryAI's avatar
Level 58

It seems like you're trying to initialize a select2 dropdown within a Livewire component and you're encountering an issue where your select2Init function is not being recognized. This could be due to the way Livewire handles scripts or a timing issue where the script is not available when the component is initialized.

Here's a solution that should work:

  1. Ensure that you have included jQuery and Select2 in your layout or component.
  2. Use Livewire's @push directive to add scripts to your layout's stack instead of using @script and @endscript tags.
  3. Make sure that your Livewire component's root element is wrapped around your select element.

Here's an example of how you can modify your component:

<div class="row" wire:ignore x-data x-init="select2Init()">
    <div class="align-items-center">
        <select
            id="mp"
            class="mp"
            wire:model="form.mPortal"
            x-ref="selectMPortals"
            multiple
        >
            @foreach($mPortals as $mp)
                <option>
                    {{ $mp }}
                </option>
            @endforeach
        </select>
    </div>
</div>

@push('scripts')
<script>
    function select2Init() {
        const select2 = $('#mp').select2({
            dropdownParent: $('#siptrunk-form'),
            language: '{{ $lang }}',
            width: '100%',
            placeholder: '{{ __('messages.Selected numbers') }}',
        });

        select2.on('change', function (e) {
            let selectedOptions = $(this).select2('data');
            let selectedTexts = selectedOptions.map(option => option.text);
            @this.set('form.mPortals', selectedTexts);
        });
    }

    document.addEventListener('livewire:load', function () {
        select2Init();
    });
</script>
@endpush

Here's what we've done:

  • We've used the @push directive to add the script to a stack that should be yielded in your layout file. Make sure your layout file has @stack('scripts') somewhere in it, usually before the closing </body> tag.
  • We've added an event listener for livewire:load to ensure that the select2Init function is called when Livewire components have finished loading.
  • We've changed the jQuery selector from this.$refs.selectMPortals to $('#mp') to directly select the element by its ID.

Make sure that your layout file includes the scripts stack like this:

<!-- Other layout content -->
@stack('scripts')
</body>
</html>

This should ensure that your custom scripts are loaded and executed after Livewire components have been initialized.

Please or to participate in this conversation.