Сторонні бібліотеки (редактори тексту, вибір дати, карти, графіки) самі змінюють DOM: додають елементи, класи, атрибути. Після наступного запиту Livewire морфить DOM за новим HTML із сервера - і затирає все, що побудувала бібліотека.
wire:ignore каже Livewire не чіпати вміст елемента при оновленнях:
<div wire:ignore>
<div x-data x-init="initEditor($el)"></div>
</div>
wire:ignore.self - ігнорувати зміни лише атрибутів самого елемента, а вміст оновлювати як звичайно.
Типовий шаблон інтеграції через Alpine:
<div wire:ignore
x-data="{ value: $wire.entangle('content') }"
x-init="
const editor = new Editor($refs.editor, { content: value });
editor.on('change', () => $wire.content = editor.getHTML());
">
<div x-ref="editor"></div>
</div>
Краще без entangle - напряму через $wire:
<div wire:ignore
x-data
x-init="
const picker = flatpickr($refs.input, {
defaultDate: $wire.date,
onChange: (dates, str) => $wire.date = str,
});
">
<input x-ref="input" type="text">
</div>
Що варто врахувати:
- напрям «сервер → бібліотека»: якщо сервер змінив значення (скинули форму), бібліотека під
wire:ignoreпро це не знає. Потрібна подія ($this->dispatch('editor-reset')) чи$wire.$watch('date', ...)в Alpine; - частота запитів:
$wire.content = ...лише змінює значення в браузері, на сервер воно піде з наступною дією.$wire.set('content', value)надсилає запит одразу - для редактора тексту це запит на кожне натискання клавіші; - знищення: бібліотеки, що підписуються на
window/document, мають прибиратися вdestroy()Alpine-компонента - інакше зwire:navigateслухачі накопичуються; wire:key, якщо таких полів кілька в циклі, - щоб при зміні списку бібліотека не опинилася «прив'язаною» до чужого рядка;- власне поле з
wire:model: обгортку можна оформити Blade-компонентом зx-modelable, тоді в шаблонах вистачить<x-date-picker wire:model="date" />.
Альтернатива - бібліотеки, створені для Livewire/Alpine (Flux, Alpine-плагіни), які вже вміють жити з морфінгом.