alpinejs / alpine

A rugged, minimal framework for composing JavaScript behavior in your markup.
https://alpinejs.dev
MIT License
27.96k stars 1.22k forks source link

Error when passing Blade Livewire property into Alpine #124

Closed ryatkins closed 4 years ago

ryatkins commented 4 years ago

I have a data table of items driven by Livewire and on an @click it displays a modal based on the "item_no" of each row. I fetch the modal data as a HTML server partial by passing the item_no to a Laravel API endpoint.

I'm attempting to use the Blade/Livewire property {{$item->item_no}} directly in my Javascript and I get the error below. I can't do a wire:ignore since I want item_no to be updated when I filter the data.

How do I use a Blade property inside my Alipine @click.prevent call below? If I remove my Blade property I don't receive this error anymore, but of course I need it.

DOMException: Failed to execute 'setAttribute' on 'Element': '@click.prevent' is not a valid attribute name.

@foreach ($items as $item)
                <tr>
                    <td>
                        <a href="" 
                        @click.prevent="                     
                            fetch('/api/items/bom/{!! $item->item_no !!}')
                            .then(response => response.text())
                            .then(html => { 
                                $refs.modal.innerHTML = html; 
                                open = true; 
                            });
                        ">
                                {{ $item->item_no }}
                         </a>
                     </td>
                    <td>{{ $item->item_desc_1 }}</td>
                    <td>{{ $item->item_desc_2 }}</td>
                </tr>
@endforeach
ryatkins commented 4 years ago

I was able to solve the issue by adding an ID to the anchor element.

<a id="{{ trim($item->item_no) }}" href="" 
                            @click.prevent="
                            fetch('/api/items/bom/{!! trim($item->item_no) !!}')
                            .then(response => response.text())
                            .then(html => { 
                                $refs.modal.innerHTML = html; 
                                open = true; 
                            });
                        ">
ryatkins commented 4 years ago

Just a follow-up with some cleaned up code and using wire:key instead of an ID.

<div x-data="modalData()" x-cloak>

@foreach ($items as $item)
                <tr wire:key="{{ trim($item->item_no) }}">
                    <td class="td normal-case">
                        <a class="text-orange-600 font-bold" href="" 
                            @click.prevent="openModal('{!! trim($item->item_no) !!}')">
                            {{ $item->item_no }}
                    </a></td>
                    <td class="td normal-case">{{ $item->item_desc_1 }}</td>
                    <td class="td normal-case">{{ $item->item_desc_2 }}</td>
                </tr>
@endforeach
    <script>
        function modalData() {

            return {              
                open: false,  
                open() { this.open = true },
                close() { this.open = false },
                isOpen() { return this.open === true },
                openModal(id) { 
                    fetch('/api/items/bom/' + id)
                            .then(response => response.text())
                            .then(html => { 
                                this.$refs.modal.innerHTML = html; 
                                this.open = true;
                            });
                 },
            }
        }
    </script>