Belajar Livewire - JavaScript & Third-Party Integration
Episode 18 of 23

Belajar Livewire - JavaScript & Third-Party Integration

Menjembatani Livewire dengan JavaScript eksternal: $this->js() untuk mengeksekusi script dari server, $wire.$entangle untuk state dua arah, serta integrasi chart dan editor teks kaya seperti tiptap/ckeditor tanpa framework JavaScript.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Livewire menghilangkan kebutuhan menulis JavaScript untuk sebagian besar aplikasi — tetapi beberapa kebutuhan tetaplah JavaScript murni: chart interaktif, editor teks kaya, peta, atau library visualisasi. Kabar baiknya, Livewire punya jembatan resmi untuk itu: $this->js() untuk memanggil JavaScript dari server, dan $wire.$entangle untuk membagi state dua arah dengan Alpine.

Filosofinya tetap: PHP tetap di kursi pengemudi. Kalian memanggil JavaScript hanya sebagai alat tampilan, bukan sebagai logika aplikasi.

$this->js(): Memanggil JavaScript dari Server

$this->js() mengeksekusi JavaScript di browser setelah aksi server selesai:

Trigger JS setelah aksi
public function save()
{
    // logika simpan...
 
    $this->js("alert('Data tersimpan!')");
}

Contoh yang lebih berguna — scroll ke elemen setelah render:

Scroll setelah aksi
public function addComment()
{
    $this->js(
        "document.getElementById('comment-form').scrollIntoView({ behavior: 'smooth' })"
    );
}

Untuk kode yang lebih kompleks, gunakan Alpine dan panggil lewat event atau $wire:

Memanggil fungsi Alpine
$this->js('showToast("Post disimpan")');

Catatan penting: string di $this->js() melewati JSON encoding, jadi aman dari XSS — jangan membangun string dengan interpolasi nilai user secara manual tanpa sanitasi.

Warning

$this->js() mengeksekusi kode di browser user. Jangan pernah menyisipkan nilai dari input user ke dalam string JavaScript tanpa escape — walau Livewire menangani banyak kasus, kebiasaan paling aman adalah memvalidasi dan sanitasi semua input yang akan masuk ke ekspresi JS.

$wire.$entangle: State Dua Arah

$wire.$entangle() menghubungkan property Livewire dengan state Alpine secara dua arah — perubahan di sisi mana pun menyinkronkan ke sisi lain:

Entangle dengan property Livewire
<div x-data="{ darkMode: $wire.$entangle('darkMode') }">
    <button type="button" @click="darkMode = !darkMode">
        <span x-show="darkMode">Mode terang</span>
        <span x-show="!darkMode">Mode gelap</span>
    </button>
</div>
Property di komponen
public bool $darkMode = false;

Saat user mengklik, state Alpine darkMode berubah dan property Livewire $darkMode ikut berubah (dan sebaliknya). Ini pola utama untuk preferensi UI yang perlu disimpan di server namun diubah cepat di client. (Di Livewire v4, @entangle Blade directive lama sudah dihapus — gunakan $wire.$entangle.)

Integrasi Chart

Chart library (Chart.js, ApexCharts, dsb.) biasanya butuh elemen DOM yang diinisialisasi sekali. Kombinasikan wire:ignore (episode 5) + $this->js():

resources/views/livewire/revenue-chart.blade.php
<div wire:ignore>
    <canvas id="revenue-chart" data-points='@json($chartData)'></canvas>
</div>
app/Livewire/RevenueChart.php
use Livewire\Attributes\Computed;
 
#[Computed]
public function chartData()
{
    return collect(Revenue::monthly())
        ->map(fn ($r) => [$r->month->format('M'), $r->total]);
}
 
public function mount()
{
    $this->js("window.initRevenueChart('revenue-chart')");
}

Pola kuncinya:

  1. wire:ignore melindungi canvas dari morphing — Livewire tidak akan menyentuh DOM chart.
  2. $this->js() memanggil inisialisasi setelah komponen ter-render.
  3. Data disuntikkan lewat data-points JSON, dibaca sekali oleh script inisialisasi.

Saat data berubah dan perlu update, kirim event ke Alpine dan panggil method update chart — tanpa membangun ulang dari nol.

Integrasi Editor Teks Kaya (tiptap/ckeditor)

Editor seperti tiptap atau CKEditor mengelola kontennya sendiri di DOM. Pola amannya: simpan konten ke property Livewire saat editor berubah, dan jangan biarkan morphing menyentuh area editor:

resources/views/livewire/post-editor.blade.php
<div x-data="{ body: $wire.$entangle('body') }"
     wire:ignore
     x-init="
         new tiptap(this.$refs.editor, {
             content: body,
             onUpdate: ({ editor }) => body = editor.getHTML()
         })
     ">
    <div x-ref="editor"></div>
</div>
  • $wire.$entangle('body') membuat konten editor dan property body saling sinkron.
  • Saat editor berubah, onUpdate menulis HTML ke body → state Livewire ikut.
  • wire:ignore memastikan morphing tidak menimpa editor saat komponen me-render ulang.

Dengan pola ini, konten editor bisa divalidasi dan disimpan sebagai data server biasa — tanpa menulis logika editor di PHP.

Integrasi Library Tanpa Framework JS

Prinsip umum untuk library pihak ketiga apa pun:

  1. Inisialisasi sekali, di elemen yang dilindungi wire:ignore.
  2. Berkomunikasi lewat $wire (dari Alpine ke Livewire) dan $this->js()/event (dari Livewire ke Alpine).
  3. Jangan biarkan morphing mengelola area yang menjadi domain library.

Contoh untuk select2/tom-select (searchable dropdown):

Integrasi tom-select
<div wire:ignore x-data="{
    init() {
        new TomSelect(this.$refs.select, {
            value: $wire.selected,
            onChange: (value) => $wire.selected = value
        })
    }
}">
    <select x-ref="select">
        @foreach ($options as $value => $label)
            <option value="{{ $value }}">{{ $label }}</option>
        @endforeach
    </select>
</div>

$wire.selected = value memperbarui property Livewire saat user memilih — dan karena wire:ignore, dropdown tidak rusak saat komponen merender ulang.

Pitfall Umum

  • Morphing menimpa DOM library: selalu bungkus area library dengan wire:ignore.
  • Inisialisasi berulang: $this->js() di mount() hanya sekali; jangan inisialisasi di setiap render.
  • @entangle di v4: sudah dihapus — gunakan $wire.$entangle.
  • Interpolasi nilai user ke JS: risiko XSS; validasi & sanitasi dulu.
  • State library disimpan di DOM saja: jika perlu disimpan/dibagi, entangle ke Livewire.

Penutup

Inti yang harus dibawa pulang:

  • $this->js() memanggil JavaScript dari server setelah aksi; aman dari XSS bila dipakai benar.
  • $wire.$entangle membagi state dua arah antara Alpine dan Livewire.
  • Integrasi chart/editor: wire:ignore + inisialisasi sekali + $wire/$this->js() untuk komunikasi.
  • Prinsip umum: library mengelola DOM-nya sendiri; Livewire tetap pemegang state.

Di episode 19 selanjutnya kita akan membahas Volt: functional API — menulis komponen dalam satu file .blade.php dengan new class extends Component, integrasi dengan Folio untuk file-based routing, serta perbandingan kapan memakai class-based vs Volt. Sampai jumpa di episode 19!