Search code examples
laraveljquery-select2laravel-livewire

Livewire doesn't sent select2 variable


I created a livewire component, in it I created a form with normal Input and multiple select with select2. I filled in the fields and selected the necessary options in select, all variables (from default input and default select) are sent except select2.

Through ddd(); it shows that they are []. Through the console, I can see that all variables, except select with select2, are sent.

What could be the problem?

<div>
    <form wire:submit.prevent="createPerson" method="POST">
        @csrf
        <div>
            {{--WORKS--}}
            <x-jet-label for="name" value="{{ __('Name') }}"></x-jet-label>
            <x-jet-input wire:model.defer="name"
                         id="name"
                         name="name"
                         type="text"
                         autocomplete="off"
                         required>
            </x-jet-input>
            @error('name') <span>{{$message}}</span> @enderror
        </div>
        <div>
            {{--WORKS---}}
            <label for="agree">{{ __('Agree?') }}</label>
            <select wire:model.defer="agree"
                    id="agree"
                    name="agree"
                    required>
                <option value="1">
                    {{ __('Yes') }}
                </option>
                <option value="0">
                    {{ __('No') }}
                </option>
            </select>
            @error('agree') <span>{{$message}}</span> @enderror
        </div>
        <div>
            {{--DOES NOT WORK--}}
            <x-jet-label for="town" value="{{ __('Town') }}"></x-jet-label>
            <select wire:model.defer="town"
                    name="town[]"
                    id="town"
                    class="select2-multiple-town"
                    style="width: 100%"
                    autocomplete="off"
                    multiple
                    required>
                @isset($items)
                    @foreach($items as $item)
                        <option value="{{ $item->id }}">{{ $item->name }}</option>
                    @endforeach
                @endisset
            </select>
            @error('town') <span class="text-sm text-red-600">{{$message}}</span> @enderror
        </div>
        <div>
            <button type="submit">{{ __('Create') }}</button>
        </div>
    </form>
</div>
@push('modals')
    <script type="text/javascript">
        function select2Init() {
            $('.select2-multiple-town').select2({
                minimumInputLength: 2
            });
        }
        document.addEventListener("DOMContentLoaded", () => {
            Livewire.hook('component.initialized', (component) => {
                select2Init();
            });
            Livewire.hook('message.processed', (message, component) => {
                select2Init();
            })
        })
    </script>
@endpush
class AddPerson extends Component
{
    #VARIABLES FROM CONTROLER
    public $items = [];

    @VARIABLES FROM COMPONENT
    public $name;
    public $agree;
    public $town = [];
   
    protected $rules = [
        'name'              => 'required',
        'agree'             => 'required',
        'town'              => 'required',
    ];

    public function createPerson()
    {
        $this->validate();
    
        Person::create([
            'name'           => $this->name,
            'agree'          => $this->agree,
            'town'           => $this->town,
        ]);

        $this->reset();

        $this->redirect(route('moderator.main'));
    }

    public function render()
    {
        return view('livewire.mod.add-person');
    }
}

Solution

  • 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. Here's a code example

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