Using Livewire with Select2 Selectpicker

Hey, if anyone is wondering how to use Livewire with older jQuery based extensions like DateTimePicker, it’s actually pretty easy in many cases.

I have projects where I’m using bootstrap themes, and a very common input for me is a selectpicker

The docs give a great writeup of how to do this:

Here’s the relevant code from the docs:

Basically you need to tell Livewire to ignore your original select item and then use javascript to hook into the changed event on your select picker. You can see the blade directive @this.set('foo', e.target.value); which is what tells your Livewire Class to set the value of your public property to what was chosen in the selectpicker.

I’ve used the same approach for datetimepickers and it works just as well.

5 Likes

Hi; How would you do that if you have select multiple?
For example, you are editing a form. Need to load old data and add one more record?

The solution is:

<script>
    $(document).ready(function() {
        $('#select2').select2();
        $('#select2').on('change', function (e) {
            var data = $('#select2').select2("val");
            @this.set('foo', data);
        });
    });
</script>

How would you deal with the case when you select a value it re-renders the component and then it is no longer a select2 but a normal select?

1 Like

I have tried that way, It’s work when I did exactly the same with that code.
But if I use it in my code it doesn’t work.

Can u help me please :frowning:

Doing this with blade components solves most problems.

The place where you want to have select.
<x:select-list wire:model="test" id="test" name="test" :messages="$tests" select-type="label"/>

Component view

<div wire:ignore class="w-full">
    <select class="form-select select2" data-minimum-results-for-search="Infinity" data-placeholder="{{__('Select your option')}}" {{ $attributes }}>
        <option></option>
            @foreach($messages as $key => $item)
                <option value="{{$item->id}}">{{$item->name}}</option>
            @endforeach
    </select>
</div>

@push('scripts')
    <script>
        $(document).ready(function() {
            $('.select2').select2({
                placeholder: '{{__('Select your option')}}',
                allowClear: true
            });
            $('.select2').on('change', function (e) {
                let elementName = $(this).attr('id');
                var data = $(this).select2("val");
                @this.set(elementName, data);
            });
        });
    </script>
@endpush
3 Likes

Does anyone have experience using this in combination with Turbolinks? The initial load of the page there are no problems, but after navigating both the script that was pushed is loaded on every page, and on return to the same page (with the select2 element) I get a “Uncaught TypeError: Cannot read property ‘set’ of undefined” on the @this.set. I’ve changed the doc ready to turbolinks:load, but I guess I am doing something fundamentally wrong. Any insights?

1 Like

I have same issue with you. I still stuck on that. have you solve that problem?

Good day, i am having problems trying to implement this, i am getting “Uncaught SyntaxError: Invalid or unexpected token” in the @this directive, i am searching but i can’t find info about that directive, neither do i get color sintaxis in my IDE, if i delete that part and put a console.log() there is not error, but neither do i get the data binding, i did even try to copy and paste the example that is in the documentation and i am getting the same error, so i am out of ideas now.

<script>
    $(document).ready(function() {
		$('.industry_select').select2();
        $('.industry_select').on('change', function (e) {
			@this.set('industry', e.target.value);
		});
    });
</script>

its a big problem select2 with livewire :frowning:

Make sure that script is in your Livewire template and also you’ll want to create a JavaScript stack if you don’t have one already and push that script to the stack. You’ll see in the examples above that there is a @push() blade directive surrounding the JavaScript.

Hello and thanks for the reply, the stack is already build, and i did try pushing, stacking (at start, end) using section, with a new stack, etc. when i use the $(’.industry_select’).select2(); the select2 is applied, is when i try to use @this directive that i got error, and i can’t even find documentation about that directive.

I would like to add that the select is inside a fully functional component, the form, with 5 input including 2 select, is send, validate, errors are show, a new row is create in the DB and it return a redirect to model.index, all these using Liveware, so liveware is working all right there.

Not sure what’s going on in your project. The directive definitely works. I made a video at Laracasts about it. Maybe this will help?

1 Like

Thanks, at the end of the video you show where is the documentation for this and what is and what it does, now i am getting error when i choose a element and the select 2 stop working and go back to a normal select, so i guess i am gonna keep using a normal select for a while, i am confident the user can find the right item in the 880 options XD.

Hi, I just found one interesting section AlpineJS documentation part, which might help very well in your case:


See sections " Ignoring DOM-changes" and " Communicating Between Livewire and JavaScript"

Basically I would use “ignore changes” method for Select2, then add a hidden input bounded to a model and finally link Select2 change events to a script, which will update hidden input with selected value in Select2 using “communication” method.

It’s sound like it could work, i am gonna give it a try later but at this moment i am looking at options to what to do with a error 419, that modal don’t look pretty.

Thank you [iAmKevinMcKee]. To expand upon this, I had other select2 selectors within my portion of a form that would update city, state, etc, when a subdivision was selected from a select 2. My issue was that the other select2 selectors would not render after a change. Only the original would render as select2. Using Livewire hook afterDomUpdate will trigger select2 on the other selectors.

    $(document).ready(function() {
        $('.js-select2-create').select2({
            tags: true,
        }).on('change', function(e){
            @this.set('subdivision_id', e.target.value);
        });
        $('.js-select2').select2();
    });
    document.addEventListener("livewire:load", function (event) {
        window.livewire.hook('afterDomUpdate', () => {
            $('.js-select2').select2();
        });
    });
1 Like

Right and if you want to pass some more parameters to select2 picker, then you may add some extra steps:

function initSelect2()
        {
            // add select2 initialization per element
            $('.select2:not(.select2-enabled)').each(function(i, obj) {
                $(obj).addClass('select2-enabled');
                select2init(obj);
            });
        }

 function select2init(selector) {

            let el = $(selector);
            let url = el.attr('ajax-url');
            let method = el.attr('method');
            $(selector).select2({...

Any example code, please