BogdanGiroe's avatar

Multiselect using Choices.js and livewire 2

I have created a select and a multiselect input and it loses the style. I have an input for selecting a program and based on what I selected it will populate the courses select(multiple). When I select a program it loses the style imediatly. What can I do?

PostsCoursesModels2.php

0 likes
3 replies
LaryAI's avatar
Level 58

It sounds like you're experiencing an issue where the styling provided by Choices.js is lost when Livewire updates the DOM. This can happen because Livewire replaces parts of the DOM to reflect the state change, which can remove the enhancements that Choices.js applies.

To solve this, you can re-initialize Choices.js after Livewire makes updates to the DOM. You can do this by listening to Livewire's updated event and then reapplying Choices.js to the select elements.

Here's an example of how you might do this:

document.addEventListener('livewire:load', function () {
    // Initialize Choices.js when the page loads
    var programSelect = new Choices('#program-select', { /* your options here */ });
    var coursesSelect = new Choices('#courses-select', { /* your options here */ });

    // Listen for Livewire update event
    Livewire.hook('element.updated', (el, component) => {
        // Check if the updated element is one of your select inputs
        if (el.id === 'program-select' || el.id === 'courses-select') {
            // Destroy the old Choices instance
            if (el.id === 'program-select') {
                programSelect.destroy();
            } else {
                coursesSelect.destroy();
            }

            // Re-initialize Choices on the updated select element
            new Choices(el, { /* your options here */ });
        }
    });
});

In your Livewire component (PostsCoursesModels2.php), make sure you have the correct wire:model for your selects. For example:

<select id="program-select" wire:model="selectedProgram">
    <!-- Options -->
</select>

<select id="courses-select" wire:model="selectedCourses" multiple>
    <!-- Options -->
</select>

Make sure to replace #program-select and #courses-select with the actual IDs of your select elements, and provide the necessary options for Choices.js initialization.

By re-initializing Choices.js after Livewire updates the select elements, you should be able to maintain the styling and functionality provided by Choices.js.

liandhas's avatar

use wire:ignore

<div x-data="{ 
		multiple: true,
        value: value,
        options: options,
        init() {
            this.$nextTick(() => {
                let choices = new Choices(this.$refs.select, {
                    removeItemButton: true,
                    placeholderValue: 'All',
                    allowHTML: false
                })
                let refreshChoices = () => {
                    let selection = this.multiple ? this.value : [this.value]
                    choices.clearStore()
                    choices.setChoices(this.options.map(({ value, label }) => ({
                        value,
                        label,
                        selected: selection.includes(value),
                    })))
                }
                refreshChoices()
                this.$refs.select.addEventListener('change', () => {
                    this.value = choices.getValue(true)
                })
                this.$watch('value', () => refreshChoices())
                this.$watch('options', () => refreshChoices())
            })
        } }" 
		class="w-full max-w-sm"
		wire:ignore
>
        <div class="min-w-0 flex-1">
            <select x-ref="select" :multiple="multiple"></select>
        </div>
</div>
1 like
BogdanGiroe's avatar

I tryed with wire:ignore but it did not populate the courses when I select a program

<!-- Courses Section -->
<div>
    <label for="courses"
           class="block text-sm font-medium text-gray-700">Courses:</label>
    <select id="courses" wire:model="selectedCoursesIds" name="coursesName[]"
            class="form-select mt-1 block w-full rounded-md border-gray-300 py-2 pl-3 pr-10 text-base focus:border-indigo-500 focus:outline-none focus:ring-indigo-500 sm:text-sm"
            multiple wire:ignore>
        <option value="">Select Courses</option>
        @if (!empty($selectedProgram))
            @foreach ($courses as $course)
                <option selected value="{{ $course->id }}">
                    {{ $course->name }}</option>
            @endforeach
        @endif
    </select>
</div>

In your example I see x-data=... This is alpine.js. I want to use choices.js

Please or to participate in this conversation.