alpinejs / alpine

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

@-directive: Uncaught (in promise) DOMException: String contains an invalid character (Livewire.js:13) #1235

Closed Yinci closed 3 years ago

Yinci commented 3 years ago

I am not entirely sure if this is more relevant to Alpine or to Livewire, but since the issue comes from Alpine I'll post it here;

For context: I have a table that displays users, and users can be softdeleted. On each user row, there are buttons to either delete or restore that user. See the code below:

@can('restore', $user)
    <form wire:submit.prevent="restore({{ $user->id }})">
        <button @click="if(!confirm('@lang('users.index.restore-confirm')')) {return false;}" type="submit" class="inline-flex items-center btn-rounded btn-green">
            <svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
            </svg>
        </button>
    </form>
@endcan
@can('delete', $user)
    <form wire:submit.prevent="destroy({{ $user->id }})">
        <button @click="if(!confirm('@lang('users.index.delete-confirm')')) {return false;}" type="submit" class="inline-flex items-center btn-rounded btn-red">
            <svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
            </svg>
        </button>
    </form>
@endcan

Upon either deleting or restoring the user, the error Uncaught (in promise) DOMException: String contains an invalid character is triggered at line 13 in Livewire.js according to the console. This breaks the whole page.

When changing @ to x-on: there is no issue.

Versions: Firefox: 87.0 (64 bits) Laravel: 8.21.0 Livewire: 2.3.0 AlpineJS: 2.8.2

SimoTod commented 3 years ago

@Yinci It's the default behaviour in Laravel. The '@' symbol has a specific meaning in blade files (You would get the same error with other frameworks): https://laravel.com/docs/8.x/blade#blade-and-javascript-frameworks (TLDR: you need to use @@)

Yinci commented 3 years ago

(TLDR: you need to use @@)

That makes sense, but it also doesn't. How come it works 95% of the time, just not in this use case?

SimoTod commented 3 years ago

Do you have an example where it works in blade without escaping the @. It shouldn't work.

Yinci commented 3 years ago

It shouldn't work.

I've been using @click literally everywhere in my code. Only this time, upon a re-load of this particular code snippet, does it cause an exception. This code snippet works on first render. If this isn't intended behaviour, then it's weird that it's working on the first render, don't you think?

SimoTod commented 3 years ago

🤷‍♂️ The laravel documentation says to escape the @ symbol so I would follow it. I personally don't use that stack but other laravel devs should be able to tell you why some times it works and some times it doesn't. Nevertheless I suspect it's not an Alpine bug.

Yinci commented 3 years ago

The laravel documentation says to escape the @ ...

That's fair enough! Makes sense, I just can't wrap my head around why it then would work in the first sense.

Nevertheless I suspect it's not an Alpine bug.

Anyhow, I suppose I'll close this as it's not really an issue, but perhaps it could be mentioned in the readme.

Yinci commented 3 years ago

Re-opening this. I've been escaping @ ever since this issue (@@click), but even then, it comes back.

Simply put: Refreshing a table that contains an @click (escaped or not), results in this exception.

ryangjchandler commented 3 years ago

@Yinci This isn't an Alpine bug as @SimoTod said before. The problem is with morphdom (the DOM diffing library Livewire uses).

If you use the long hand equivalent, x:on everything should work correctly.

calebporzio commented 3 years ago

Yeah, turns out element.setAttribute doesn't allow @ symbols. So any time morphdom tries to set a new @on attribute for any reason, the browser throws this error.

It's a pity because those attributes are perfectly fine in HTML when the element is created.

Will need to explore alternatives to .setAttribute if there are any