I got error making multiselect in laravel / livewire / alpinejs app

40 views Asked by At

In laravel 10/ livewire 3/ tailwindcss 3 app I need to make multiselect working like select2, but without jquery used, whuch is required by select2.

I found this https://github.com/alexpechkarev/alpinejs-multiselect code and try to implement in my blade file of simple livewire component I created with command :

php artisan make:livewire Test

I did not modify component file, but in blade file I edited :

<div class="admin_page_container" id="app_image_admin_page_container" x-cloak>

    <div class="w-full" x-data="alpineMuliSelect({selected:['te_11', 'te_12'], elementId:'multSelect'})">

        <select style="display:none;" id="multSelect">
            <option value="te_1" data-search="arsenal">Arsenal</option>
            <option value="te_3" data-search="Tottenham Hotspur Spurs">Spurs</option>
            <option value="te_3" data-search="Manchester City">Man City</option>
        </select>
    </div>
</div>

and I added js code into resources/js/app.js :

import './bootstrap';
import Alpine from 'alpinejs';

window.Alpine = Alpine;

import focus from '@alpinejs/focus'

import flatpickr from "flatpickr";


// I ADDED THESE LINES BEFORE Alpine.start() method
document.addEventListener("alpine:init", () => {
    window.Alpine.data("alpineMuliSelect", (obj) => ({
        elementId: obj.elementId,
        options: [],
        selected: obj.selected,
        selectedElms: [],
        show: false,
        search: '',
        open() {
            this.show = true
        },
        close() {
            this.show = false
        },
        toggle() {
            this.show = !this.show
        },
        isOpen() {
            return this.show === true
        },

        // Initializing component
        init() {
            const options = document.getElementById(this.elementId).options;
            for (let i = 0; i < options.length; i++) {

                this.options.push({
                    value:  options[i].value,
                    text:   options[i].innerText,
                    search: options[i].dataset.search,
                    selected: Object.values(this.selected).includes(options[i].value)
                });

                if (this.options[i].selected) {
                    this.selectedElms.push(this.options[i])
                }
            }

            // searching for the given value
            this.$watch("search", (e => {
                this.options = []
                const options = document.getElementById(this.elementId).options;
                Object.values(options).filter((el) => {
                    var reg = new RegExp(this.search, 'gi');
                    return el.dataset.search.match(reg)
                }).forEach((el) => {
                    let newel = {
                        value: el.value,
                        text: el.innerText,
                        search: el.dataset.search,
                        selected: Object.values(this.selected).includes(el.value)
                    }
                    this.options.push(newel);
                })
            }));
        },
        // clear search field
        clear() {
            this.search = ''
        },
        // deselect selected options
        deselect() {
            setTimeout(() => {
                this.selected = []
                this.selectedElms = []
                Object.keys(this.options).forEach((key) => {
                    this.options[key].selected = false;
                })
            }, 100)
        },
        // select given option
        select(index, event) {
            if (!this.options[index].selected) {
                this.options[index].selected = true;
                this.options[index].element = event.target;
                this.selected.push(this.options[index].value);
                this.selectedElms.push(this.options[index]);

            } else {
                this.selected.splice(this.selected.lastIndexOf(index), 1);
                this.options[index].selected = false
                Object.keys(this.selectedElms).forEach((key) => {
                    if (this.selectedElms[key].value == this.options[index].value) {
                        setTimeout(() => {
                            this.selectedElms.splice(key, 1)
                        }, 100)
                    }
                })
            }
        },
        // remove from selected option
        remove(index, option) {
            this.selectedElms.splice(index, 1);
            Object.keys(this.options).forEach((key) => {
                if (this.options[key].value == option.value) {
                    this.options[key].selected = false;
                    Object.keys(this.selected).forEach((skey) => {
                        if (this.selected[skey] == option.value) {
                            this.selected.splice(skey, 1);
                        }
                    })
                }
            })
        },
        // filter out selected elements
        selectedElements() {
            return this.options.filter(op => op.selected === true)
        },
        // get selected values
        selectedValues() {
            return this.options.filter(op => op.selected === true).map(el => el.value)
        }
    }));
});


Alpine.plugin(focus)
Alpine.start();

But I got error :

livewire.js?id=5d8beb2e:1192 Alpine Expression Error: alpineMuliSelect is not defined

Expression: "alpineMuliSelect({selected:['te_11', 'te_12'], elementId:'multSelect'})"

Not shure in which way have I to describe alpineMuliSelect method ?

UPLOADED EXAMPLE :

I uploaded test app with this example at https://github.com/sergeynilov/TestApp

Standart laravel/livewire app. To instal alpinejs I used command

npm install alpinejs

Running server with command :

php artisan serve 

I open home page at http://127.0.0.1:8000 where I put select input

I created a component :

php artisan livewire:make HomePage  

Added small count component just be sure that alpine works ok
I left misspeling in “alpineMuliSelect” function .

In resources/js/app.js I added definition of “alpineMuliSelect”. I got the same error as on my page.

UPDATED INFO : I removed alpinejs from package.json and all alpinejs code from resources/js/app.js

Now I do not have any errors in console, but select input is not visible and checking in browser I see it has

style="display:none;"

enter image description here from

I added debugging in resources/js/app.js :

import './bootstrap';
document.addEventListener("alpine:init", () => {
    console.log('resources/js/app.js ::')  // I SEE THIS MESSAGE
    window.Alpine.data("alpineMuliSelect", (obj) => ({
        elementId: obj.elementId,
        options: [],
        selected: obj.selected,
        selectedElms: [],
        show: false,
        search: '',
        open() {
            console.log('resources/js/app.js OPEN::')
            this.show = true
        },
        close() {
            console.log('resources/js/app.js CLOSE::')
            this.show = false
        },
        toggle() {
            this.show = !this.show
        },
        isOpen() {
            console.log('resources/js/app.js isOpen::')
            return this.show === true
        },

        // Initializing component
        init() {
            const options = document.getElementById(this.elementId).options;
            console.log('resources/js/app.js init options::') // I SEE THIS MESSAGE
            console.log(options)
            for (let i = 0; i < options.length; i++) {
                ...

and checking output I see that alpineMuliSelect is triggered

enter image description here

After I removed

style="display:none;"

from select input - in this case I see usual select input visible.

Any ideas ?

0

There are 0 answers