Anda di halaman 1dari 127

Dokumentasi AlpineJS V3

bahasa Indonesia

Your new, lightweight, JavaScript framework.

https://alpinejs.dev/start-here
Daftar Isi
Start Here ........................................................................................................................................................ 1

Upgrade from V2 ...................................................................................................................................... 9

Essentials ....................................................................................................................................................... 17

Installation ............................................................................................................................................... 17

State ............................................................................................................................................................ 18

Templating .............................................................................................................................................. 21

Event .......................................................................................................................................................... 26

Lifecycle ................................................................................................................................................... 28

Directives ....................................................................................................................................................... 31

x-data ......................................................................................................................................................... 31

x-init ........................................................................................................................................................... 34

x-show ...................................................................................................................................................... 36

x-bind.........................................................................................................................................................37

x-on ............................................................................................................................................................. 41

x-text.......................................................................................................................................................... 48

x-html ....................................................................................................................................................... 49

x-modelable ........................................................................................................................................ 54

x-for ............................................................................................................................................................ 54

x-transition ............................................................................................................................................ 56

x-effect..................................................................................................................................................... 59

x-ignore ................................................................................................................................................... 60

x-ref ............................................................................................................................................................ 60

x-cloak....................................................................................................................................................... 61

x-teleport ................................................................................................................................................ 62

x-id .............................................................................................................................................................. 65

Magics ........................................................................................................................................................... 66

i
$el ................................................................................................................................................................ 66

$refs ........................................................................................................................................................... 66

$store ........................................................................................................................................................ 66

$watch ..................................................................................................................................................... 67

$dispatch ............................................................................................................................................... 69

$nextTick ................................................................................................................................................. 70

$root............................................................................................................................................................. 71

$data .......................................................................................................................................................... 72

$id ................................................................................................................................................................. 72

Globals .......................................................................................................................................................... 76

Alpine.data ............................................................................................................................................ 76

Alpine.store ........................................................................................................................................... 79

Alpine.bind .............................................................................................................................................. 81

Plugin.............................................................................................................................................................. 83

Mask Plugin ........................................................................................................................................... 83

Intersect Plugin ................................................................................................................................... 85

x-intersect.............................................................................................................................................. 86

Persist Plugin ........................................................................................................................................ 89

Focus Plugin.......................................................................................................................................... 94

Collapse Plugin................................................................................................................................. 100

Morph Plugin ....................................................................................................................................... 102

Advanced.................................................................................................................................................... 110

Reactivity ................................................................................................................................................ 110

Extending ................................................................................................................................................ 112

Async ......................................................................................................................................................... 121

CSP (content security policy) ................................................................................................. 122

ii
Start Here
Buat sebuah berkas (file) HTML kosong dimanapun di komputer anda
dengan nama seperti: i-love-alpine.html

Gunakan sebuah teks editor, isi berkas dengan konten ini:


<html>
<head>
<script
defer
src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"
></script>
</head>
<body>
<h1 x-data="{ message: 'I ❤️ Alpine' }" x-text="message"></h1>
</body>
</html>;

buka file di peramban web, jika anda melihat I ❤️ Alpine Anda siap
untuk berderu!

Kini Anda telah memiliki set up untuk bermain, Ayo lihat pada tiga contoh
praktek sebagai dasar untuk mengajari Anda dasar-dasar Alpine. Pada
akhir latihan ini, Anda seharusnya lebih dari lebih dari cukup untuk mulai
membangun aplikasi anda sendiri. Ayo.

1. Membangun sebuah penghitung

2. membangun ah ah sebuah dropdown

3. membangun sebuah input pencarian

Membangun Sebuah Penghitung

Ayo mulai dengan sebuah komponen “counter” sederhana untuk


mendemonstrasikan dasar-dasar state dan event listening di Alpine, dua
fungsi inti.

Masukkan kdoe berikut ke tag <body>


<div x-data="{ count: 0 }">
<button x-on:click="count++">Increment</button>

<span x-text="count"></span>
</div>;

1
Sekarang Anda dapat melihat dengan 3 bits dari Alpine ditaburi ke dalam
HTML ini, ini kita telah membuat sebuah komponen “counter”. Ayo kita
apa yang terjadi secara singkat:

Declaring data
<div x-data="{ count: 0 }"></div>
Semua di dalam Alpine dimulai dengan direktif x-data. Di dalam x-data , di
JavaScript biasa, anda mendeklarasikan sebuah objek data yang yang
akan dan dilacek oleh Alpine.

Setiap properti di dalam objek ini akan dibuat tersedia untuk direktif lain di
dalam elemen HTML ini. Sebagai tambahan, ketika salah satu properti
berubah, semua yang bergantung padanya akan berubah juga.

Ayo lihat pada x-on dan lihat bagaimana x-on dapat diakses
dan mengubah properti count dari atas:

Listening for events


<button x-on:click="count++">Increment</button>;
x-on adalah sebuah direktif yang yang dapat anda gunakan untuk
mendengarkan (listen) event apapun di sebuah elemen. Kita
mendengarkan sebuah event click pada kasus ini, jadi punya kita tampak
seperti x-on:click.

Anda dapat mendengarkan event yang lain sepertinya anda


bayangkan. Contoh, mendengarkan sebuah event mouseenter tampak
seperti ini x-on:mouseenter.

ketika event click terjadi, Alpine akan memanggil ekspresi JavaScript


yang terkait, count++ kasus kita. Seperti yang Anda lihat, kita memiliki
akses langsung ke data yang dideklarasikan dalam ekspresi x-data.

*anda akan sering melihat @ alih-alih x-on:. Ini adalah


kependekan, syntax yang memudahkan yang banyak digunakan. Untuk
saat ini pada dokumentasi ini akan menggunakan @ alih-alih: x-on:

Reacting to changes
<h1 x-text="count"></h1>;
x-text adalah sebuah direktif Alpine yang Anda dapat gunakan untuk
mengatur konten teks dari elemen ke hasil dari ekspresi JavaScript.

2
Pada kasus ini, kita memberitahu Alpine untuk selalu memastikan konten
dari tag h1 mencerminkan nilai dari properti count.
jika belum jelas, x-text, seperti kebanyakan direktif menerima ekspresi
JavaScript polos atau biasa sebagai sebuah argumen. Sebagai
contoh, Anda bisa mengatur konten ke x-text="count * 2" dan teks konten
dari h1 kini akan selalu dua kali dari nilai count.

Membangun Sebuah Dropdown

Kini Anda telah melihat beberapa Apa fungsi dasar, Ayo lanjutkan dan
lihat pada direktif Alpine yang penting: x-show, dengan membangun
sebuah komponen “dropdown” yang dibuat secara perlahan.

Masukkan kode berikut ke dalam tag <body>:

<div x-data="{ open: false }">


<button @click="open = ! open">Toggle</button>

<div x-show="open" @click.outside="open = false">Contents...</div>


</div>

jika anda memuat komponen ini, anda mestinya melihat “Contents…”


yang disembunyikan secara default. Anda dapat beralih (toggle)
menampilkan konten tersebut di halaman dengan klik tombol “Toggle”.

Directif x-data dan x-on dan harusnya familiar dengan anda dari contoh
sebelumnya jadi kita akan melewati penjelasan ini.

Toggling element

<div x-show="open" ...>Contents...</div>

x-show merupakan direktif yang sangat kuat di Alpine yang dapat


digunakan untuk menampilkan dan menyembunyikan blok HTML pada
sebuah halaman berdasarkan dari sebuah ekspresi JavaScript, pada
kasus kita: open.

Listening for a click outside

<div ... @click.outside="open = false">Contents...</div>

3
anda akan menyadari sesuatu yang baru pada contoh ini .outside.
Banyak direktif di Alpine menerima modifier yang disambung (chained) ke
akhir direktif dan dipisahkan dengan titik.

Pada kasus ini, .outside memberitahu Alpine alih-alih mendengarkan


sebuah klik DI DALAM <div>, untuk mendengarkan klik hanya jika terjadi di
DI LUAR <div>.

Ini merupakan sebuah helper yang dibangun ke Alpine karena ini umum
dibutuhkan dan diimplementasikan ini dengan tangan sangat
menjengkelkan dan kompleks.

Membangun Sebuah Input Pencarian

Ayo sekarang membangun komponen yang lebih kompleks dan


memperkenalkan direktif dan pola lain.

Tambahkan kode berikut ke dalam tag <body>:

<div
x-data="{
search: '',

items: ['foo', 'bar', 'baz'],

get filteredItems() {
return this.items.filter(
i => i.startsWith(this.search)
)
}
}"
>
<input x-model="search" placeholder="Search...">

<ul>
<template x-for="item in filteredItems" :key="item">
<li x-text="item"></li>
</template>
</ul>
</div>

Secara bawaan semua “items” (foo, bar, dan baz) akan ditampilkan di
halaman tapi anda dapat menyaringnya dengan mengetik ke dalam

4
input text. Ketika anda menulis, daftar item akan berubah mencerminkan
Apa yang anda cari.

Kini ini ada banyak hal yang terjadi di sini, ayo lihat potongan ini bagian
demi bagian.

Multi line formatting

Hal pertama yang ingin saya tekankan adalah bahwa x-data kini lebih
banyak dari sebelumnya. Untuk memudahkan menulis dan membaca,
kita memecahnya ke dalam beberapa baris di HTML kita. Ini sepenuhnya
opsional dan kita akan berbicara lebih banyak tentang bagaimana
menghindari masalah ini bersama tapi untuk sekarang kita akan
membiarkan semua dari javascript ini secara langsung di HTML.

Binding to inputs

<input x-model="search" placeholder="Search...">

anda akan menyadari sebuah directive baru yang belum Anda lihat
sebelumnya: x-model

x-model digunakan untuk “bind” (mengikat ) nilai dari sebuah elemen input
dengan properti data search dari x-data="{ search: '', ... }" pada kasus
kita.

Ini berarti kapanpun nilai berubah nilai dari “search” akan berubah
mencerminkannya.

x-model memiliki lebih banyak kemampuan daripada contoh sederhana


ini.

Computed properties using getters

Lanjut sedikit, aku lebih suka menarik perhatian anda ke items dan
filteredItems properti dari direktif x-data.

{
...
items: ['foo', 'bar', 'baz'],

get filteredItems() {

5
return this.items.filter(
i => i.startsWith(this.search)
)
}
}

items properti harusnya sudah cukup jelas. Di sini ini kita mengatur nilai
items ke array JavaScript dari 3 item berbeda (foo, bar, and baz).

Bagian menarik dari potongan ini adalah properti filteredItems.

Dilambangkan dengan awalan get untuk properti ini, filteredItems adalah


sebuah properti “getter” di objek ini. Ini berarti kita dapat mengakses
filteredItems jika ini merupakan properti normal didata objek kita, tapi
ketika kita melakukannya JavaScript akan mengevaluasi fungsi yang
disediakan di belakang layar dan mengembalikan hasil.

Ini sangat diterima untuk melupakan get dan pakai method ini saja yang
dapat anda ada panggil dari template, tapi beberapa lebih suka
penulisan yang lebih baik dari getter.

Sekarang lihat ke dalam getter filteredItems dan pastikan kita pahami apa
yang terjadi di sana:

return this.items.filter((i) => i.startsWith(this.search));

Ini semua adalah JavaScript biasa. Kita pertama mendapatkan sebuah


array dari items (foo, bar, and baz) dan menyaring mereka menggunakan
callback yang disediakan i => i.startsWith(this.search).

Dengan mengoper callback ini ke filter, kita memberitahu JavaScript


untuk hanya mengembalikan items yang dimulai dengan string:
this.search, yang kita lihat dengan x-model kan selalu mencerminkan nilai
dari input.

Anda mungkin sadar sampai sekarang kita belum menggunakan this.


untuk referensi properti. Meskipun karena kita bekerja secara langsung di
dalam objek x-data, kita harus mereferensi properti manapun
menggunakan this.[property] bukan hanya [property].

6
Karena Alpine adalah sebuah framework “reaktif”. Kapanpun nilai dari
this.search berubah, bagian dari template yang menggunakan
filteredItems otomatis diperbarui.

Looping Elements

Kini kita telah mengerti data bagian dari komponen kita, ayo pahami apa
yang terjadi di dalam template yang memungkinkan kita untuk melakukan
pengulangan (loop) melalui filteredItems di halaman.

<ul>

<template x-for="item in filteredItems">

<li x-text="item"></li>

</template>

</ul>;

Hal pertama yang disadari disini adalah direktif x-for. Ekspresi x-for
mengambil bentuk berikut [item] in [items] ketika [item] dari data array
manapun, dan [item] adalah nama variabel yang akan ditugaskan
sebagai sebuah iterasi di dalam pengulangan.

Juga disadari bahwa x-for dideklarasikan pada elemen <template> dan


tidak secara langsung di <li>. Ini adalah syarat dari penggunaan x-for.
Ini memungkinkan Alpine untuk mengambil manfaat dari perilaku yang
telah ada dari tag <template> dalam peramban. Ini adalah keuntungan.

Sekarang elemen apapun di dalam tag <template> akan diulangi untuk


setiap item di dalam filteredItems dan semua ekspresi dievaluasi di dalam
perulangan yang memiliki akses langsung ke variabel iterasi(dalam hal ini
ini item)

Recap

Jika anda sampai sejauh ini, anda telah mengetahui direktif berikut
didalam Alpine:

 x-data
 x-on
 x-text
 x-show
7
 x-model
 x-for

Itu merupakan permulaan yang bagus meskipun ada banyak direktif


untuk di tenggelamkan ke dalam gigi anda. Cara terbaik untuk menyerap
Alpine adalah membaca dokumentasi ini. Tidak butuh untuk menyisir
setiap kata tapi jika paling tidak Anda melirik ke setiap halaman anda
akan lebih BANYAK efektif ketika menggunakan Alpine

Happy coding!

8
Upgrade from V2
Di bawah ini merupakan panduan lengkap dari banyak perubahan dan
didalam Alpine versi 3 tapi jika anda lebih suka sesuatu yang lebih hidup
anda dapat meninjau semua perubahan serta fitur baru di versi 3 dengan
menonton Alpine d 2021 itu future of Alpine keynote:

https://youtu.be/WixS4JXMwIQ

Perbaikan dari versi 2 ke versi 3 harusnya tidak sulit. Pada banyak kasus
TIDAK ADA yang dilakukan di kode anda untuk menggunakan versi 3. Di
bawah ini adalah daftar lengkap dari perubahan dan depresiasi dalam
urutan dari bagaimana pengguna akan berdampak pada perubahan ini:

*catat jika Anda menggunakan laravel livewire dan Alpine bersama ,untuk
menggunakan versi 3 dari Alpine, anda akan butuh meningkatkan livewire
versi 2.5.1 itu itu atau di atasnya

Breaking Changes

 $el kini selalu element saat ini

 Secata otomtis mengevaluasi fungsi $init() yang didefinisikan pada


data objek

 Perlu memmanggil Alpine.start() setelah import

 x-show.transition sekarang x-transition

 x-if tidak lagi mendukung x-transition

 x-data lingkup berjenjang

 x-init tidak lagi menerima sebuah return callback

 Mengembalikan false dari event handler tidak lagi implisit


“preventDefault”

 x-spread sekarang x-bind

 x-ref tidak lagi mendukung binding

 Gunakan global lifecycle event alih-alih Alpine.deferLoadingAlpine()

 IE11 tidak lagi didukung

$el kini selalu Element saat ini

9
$el kini selalu merepresentasikan elemen dari ekspresi yang dieksekusi,
bukan root elemen dari komponen. Ini akan mengganti kebanyakan dari
penggunaan dari x-ref pada kasus ketika Anda masih ingin mengakses
root dari komponen anda dapat menggunakan $root contoh:
<!-- 🚫 Before -->

<div x-data>

<button @click="console.log($el)"></button>

<!-- In V2, $el would have been the <div>, now it's the <button> -->

</div>

<!-- ✅ After -->

<div x-data>

<button @click="console.log($root)"></button>

</div>

Untuk pengalaman upgrade yang lebih lembut Anda dapat mengganti


semua instances dari $el dengan magic custom yang dinamakan $root.

Secara Otomatis Mengevaluasi Fungsi Init() Yang Didefinisikan Pada


Data Objek

Sebuah pola umum di versi 2 untuk secara manual memanggil init()


(atau umumnya bernama method) pada sebuah objek x-data.

pada versi 3 Alpine akan secara otomatis memanggil method init() pada
data objek.
<!-- 🚫 Before -->
<div x-data="foo()" x-init="init()"></div>

<!-- ✅ After -->


<div x-data="foo()"></div>

<script>
function foo() {
return {
init() {
//
}
}
}
</script>

10
Perlu Untuk Memanggil Alpine.Start() Setelah Impor
jika anda ada telah mengimpor Alpine versi 2 dari NPM, Anda kini butuh
untuk secara manual memanggil Alpine.start() pada versi 3. Ini tidak
akan berdampak pada anda ada jika Anda menggunakan Alpine file atau
CDN dari tag <template>.
// 🚫 Before
import "alpinejs";

// ✅ After
import Alpine from "alpinejs";

window.Alpine = Alpine;

Alpine.start();

x-show.transition kini x-transition

Semua kemudahan yang disediakan oleh Helper x-show.transition... yang


masih tersedia, tapi kini dari sebuah API yang lebih bersatu: x-transition.
<!-- 🚫 Before -->
<div x-show.transition="open"></div>
<!-- ✅ After -->
<div x-show="open" x-transition></div>

<!-- 🚫 Before -->


<div x-show.transition.duration.500ms="open"></div>
<!-- ✅ After -->
<div x-show="open" x-transition.duration.500ms></div>

<!-- 🚫 Before -->


<div x-show.transition.in.duration.500ms.out.duration.750ms="open"></div>
<!-- ✅ After -->
<div
x-show="open"
x-transition:enter.duration.500ms
x-transition:leave.duration.750ms
></div>

x-if tidak lagi mendukung x-transition

Kemampuan transisi elemen dalam dan menambahkan sebelum atau


setelah di hapus dari DOM tidak lagi tersedia di Alpine.

11
Ini adalah sebuah fitur yang hanya diketahui beberapa orang, apalagi
digunakan.

Karena transisi sistem sangatlah kompleks, lebih masuk akal dari


perspektif perawatan untuk hanya mendukung transisi elemen dengan x-
show

<!-- 🚫 Before -->

<template x-if.transition="open">

<div>...</div>

</template>

<!-- ✅ After -->

<div x-show="open" x-transition>...</div>

x-data lingkup berjenjang

Lingkup (scope) yang telah didefinisikan dalam x-data kini tersedia ke


semua children kecuali kalau ditindih oleh ekspresi x-data bersarang.
<!-- 🚫 Before -->

<div x-data="{ foo: 'bar' }">

<div x-data="{}">

<!-- foo is undefined -->

</div>

</div>

<!-- ✅ After -->

<div x-data="{ foo: 'bar' }">

<div x-data="{}">

<!-- foo is 'bar' -->

</div>

</div>

x-init Tidak Lagi Menerima Sebuah Return Callback

Sebelum versi 3 jika x-init menerima sebuah nilai yang dikembalikan


yang typeof “fungsi”. Ini akan mengeksekusi colback setelah Alpine selesai
menginisialisasi semua direktif lain di dalam tree. Kini ini anda harus
12
secara manual memanggil $nextTick() untuk mendapat perilaku. tersebut.
x-init tidak lagi “mengembalikan nilai awal”.

<!-- 🚫 Before -->


<div x-data x-init="() => { ... }">...</div>

<!-- ✅ After -->


<div x-data x-init="$nextTick(() => { ... })">...</div>

Mengembalikan false dari event handler tidak lagi implisit


“preventDefault”

Alpine versi 2 mengamati sebuah nilai return dari false untuk menjalankan
preventDefault pada event ini sesuai dengan standar perilaku native inline
listener:

<... oninput="someFunctionThatReturnsFalse()">. Alpine versi 3 tidak lagi


mendukung API ini. Kebanyakan orang tidak tahu ini ada dan karena itu
merupakan perilaku yang mengejutkan.
<!-- 🚫 Before -->
<div x-data="{ blockInput() { return false } }">
<input type="text" @input="blockInput()">
</div>

<!-- ✅ After -->


<div x-data="{ blockInput(e) { e.preventDefault() }">
<input type="text" @input="blockInput($event)">
</div>

x-spread sekarang bernama x-bind

Salah satu dari cerita Alpine untuk menggunakan ulang fungsionalitasnya


adalah abstraksi Alpine direktif ke dalam objek dan dan menerapkannya
ke dalam elemen dengan x-spread. Perilaku ini masih sama kecuali kini x-
bind (dengan tanpa atribut khusus) adalah API alih-alih x-spread.

<!-- 🚫 Before -->


<div x-data="dropdown()">
<button x-spread="trigger">Toggle</button>

<div x-spread="dialogue">...</div>
</div>

<!-- ✅ After -->


<div x-data="dropdown()">
13
<button x-bind="trigger">Toggle</button>

<div x-bind="dialogue">...</div>
</div>

<script>
function dropdown() {
return {
open: false,

trigger: {
'x-on:click'() { this.open = ! this.open },
},

dialogue: {
'x-show'() { return this.open },
'x-bind:class'() { return 'foo bar' },
},
}
}
</script>
Gunakan life cycle event global alih-alih Alpine.deferLoadingAlpine()
<!-- 🚫 Before -->
<script>
window.deferLoadingAlpine = startAlpine => {
// Will be executed before initializing Alpine.

startAlpine()

// Will be executed after initializing Alpine.


}
</script>

<!-- ✅ After -->


<script>
document.addEventListener('alpine:init', () => {
// Will be executed before initializing Alpine.
})

document.addEventListener('alpine:initialized', () => {
// Will be executed after initializing Alpine.
})
</script>

14
x-ref tidak lagi mendukung binding

di Alpine versi 2 untuk kode di bawah


<div x-data="{options: [{value: 1}, {value: 2}, {value: 3}] }">
<div x-ref="0">0</div>
<template x-for="option in options">
<div :x-ref="option.value" x-text="option.value"></div>
</template>

<button @click="console.log($refs[0], $refs[1], $refs[2],


$refs[3]);">Display $refs</button>
</div>

setelah Klik tombol semua $refs ditampilkan. Meskipun, di Alpine versi 3 ini
mungkin untuk mengakses $refs untuk elemen yang dibuat secara statis,
jadi hanya ref pertama yang dikembalikan seperti yang diharapkan

IE11 tidak lagi didukung

Alpine kini secara resmi tidak lagi mendukung Internet Explorer 11. Jika
anda butuh dukungan untuk IE 11 kami merekomendasikan untuk tetap
menggunakan Alpine versi 2

Deprecated APIs

Dua API berikut masiht tetap berfungsi di versi 3 tapi dipertimbangkan


untuk depresiasi dan akan dihapus pada saat tertentu di masa depan

event listener modifier .away harus diganti menjadi .outside.


<!-- 🚫 Before -->
<div x-show="open" @click.away="open = false">
...
</div>

<!-- ✅ After -->


<div x-show="open" @click.outside="open = false">
...
</div>

lebih suka Alpine.data() ke penyedia data fungsi Alpine global


<!-- 🚫 Before -->
<div x-data="dropdown()">
...
</div>

15
<script>
function dropdown() {
return {
...
}
}
</script>

<!-- ✅ After -->


<div x-data="dropdown">
...
</div>

<script>
document.addEventListener('alpine:init', () => {
Alpine.data('dropdown', () => ({
...
}))
})
</script>

*catat bahwa anda butuh untuk mendefinisikan ekstensi


Alpine.data() SEBELUM anda memanggil Alpine.start().

16
Essentials
Installation
Ada dua cara untuk memasukkan Alpine ke dalam proyek anda:

1. memasukkannya dari tag <script>

2. mengimpornya sebagai module

Dua-duanya valid, ini tergantung pada kebutuhan project dan selera


Developer

Dari script Tag

Ini adalah cara termudah untuk memulai Alpine. Mmemasukkan tag


<script> deskripsi berikut di dalam head dari halaman html anda.

<html>
<head>
...

<script defer
src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
</head>
...
</html>
*jangan lupa attirubte “defer” di tag <script>.

Perhatikan <script> dalam tautan CDN yang disediakan. Script ini akan
mengambil versi terakhir dari Alpine versi 3. Untuk produksi yang stabil,
direkomendasikan anda menulis versi terakhir di tautan CDN.
<script defer
src="https://unpkg.com/alpinejs@3.10.2/dist/cdn.min.js"></script>;

itu saja! kini Alpine tersedia untuk digunakan di halaman anda

Sebagai Sebuah Modul

Jika Anda lebih suka dengan pendekatan yang lebih kuat Anda dapat
menginstal Alpine melalui NPM dan mengimpor nya ke dalam sebuah
bundel.

Jalankan perintah berikut untuk menginstalnya


npm install alpinejs
impor Alpine kedalam bundel dan inisiasi seperti ini:
import Alpine from "alpinejs";

17
window.Alpine = Alpine;

Alpine.start();

* window.Alpine = Alpine adalah opsional tapi ini bagus untuk memiliki


kebebasan dan flexibility seperti ketika mengutak-atik dengan Alpine dari
devtools untuk contoh

* jika anda telah mengimpor Alpine kedalam sebuah bundel Anda harus
memastikan anda telah mendaftarkan ektensi apapun DI ANTARANYA
Ketika anda import objek global Alpin , dan ketika anda inisiasi Alpine
dengan memanggil Alpine.start().

State
State (data javascript yang Alpine awasi perubahannya) merupakan inti
dari semua yang anda lakukan di Alpine. Anda dapat menyediakan data
lokal kesebuah chunk dari HTML atau membuatnya tersedia secara global
untuk digunakan dimanapun di halaman Anda menggunakan x-data atau
Alpine.store().

Local state

Alpine memungkinkan anda untuk mendeklarasikan sebuah block state


HTML dalam sebuah atribut x-data tunggal tanpa perlu meninggalkan
mark up anda.

Ini adalah contoh dasar

<div x-data="{ open: false }">...</div>;

Sekarang syntax Alpine lainnya atau dalam elemen ini akan dapat
mengakses open. Dan seperti yang Anda duga ketika open berubah untuk
alasan apapun semua yang bergantung padanya akan bereaksi secara
otomatis.

18
Data bersarang

Data dapat bersarang di Alpine, sebagai contoh, jika anda memiliki dua
elemen dengan Alpine data terlampir (satu didalam lainnya) Anda dapat
mengakses datanya parent dalam elemen child.

<div x-data="{ open: false }">


<div x-data="{ label: 'Content:' }">
<span x-text="label"></span>
<span x-show="open"></span>
</div>
</div>;

Ini mirip dengan scoping di Javascript sendiri (kode dalam sebuah fungsi
dapat mengakses variabel yang dideklarasikan di luar fungsi tersebut).

Seperti yang mungkin anda duga, jika child memeliki property data yang
cocok dengan properti parent, properti child akan diutamakan.

Elemen Data Tunggal

Meskipun ini terlihat cukup jelas bagi sebagian orang, tapi pantas untuk
disebutkan bahwa data Alpine dapat digunakan dengan di dalam elemen
yang. Sebagai contoh

<button x-data="{ label: 'Click Here' }" x-text="label"></button>;

Alpine tanpa-data

Terkadang Anda mungkin ingin untuk menggunakan fungsionalitas Alpine


tapi tidak butuh data reaktif apapun, pada kasus ini anda dapat memilih
untuk tidak menulis ekspresi seluruhnya x-data. Sebagai contoh:

<button x-data @click="alert('I\'ve been clicked!')">Click Me</button>

Re-usable data

Ketika menggunakan Alpine, anda mungkin menemukan untuk


menggunakan ulang chunk data atau/dan dan template yang sesuai.

19
Jika Anda menggunakan framework seperti Rails atau Laravel, Alpine
pertama merekomendasikan bahwa anda ekstrak seluruh block html ke
dalam template sebagian atau termasuk.

Jika untuk beberapa alasan itu tidak ideal untuk anda atau anda tidak
dalam templating environment back-end, Alpine memungkinkan anda
untuk mendaftarkan secara global dan menggunakan ulang porsi data
dari komponen menggunakan Alpine.data(...).

Alpine.data("dropdown", () => ({
open: false,

toggle() {
this.open = !this.open;
},
}));

kini Anda telah mendaftarkan “dropdown” data, Anda dapat


menggunakannya di dalam mark up di banyak tempat sesuka anda:

<div x-data="dropdown">
<button @click="toggle">Expand</button>

<span x-show="open">Content...</span>
</div>

<div x-data="dropdown">
<button @click="toggle">Expand</button>

<span x-show="open">Some Other Content...</span>


</div>

Global State

Jika Anda berharap untuk membuat beberapa data tersedia di setiap


komponen di halaman anda, anda dapat menggunakan fitur “global
store” Alpine.

Anda dapat mendaftarkan sebuah store menggunakan Alpine.store(...)


dan mencerminkan satu dengan method magic $store()

Ayo lihat contoh sederhana pertama kita akan mendaftarkan store secara
global:

20
Alpine.store("tabs", {
current: "first",

items: ["first", "second", "third"],


});

sekarang kita dapat mengakses atau memodifikasi data dari manapun


pada halaman kita

<div x-data>
<template x-for="tab in $store.tabs.items">
...
</template>
</div>

<div x-data>
<button @click="$store.tabs.current = 'first'">First Tab</button>
<button @click="$store.tabs.current = 'second'">Second Tab</button>
<button @click="$store.tabs.current = 'third'">Third Tab</button>
</div>

Templating

Alpine menawarkan sebuah directive yang berguna untuk memanipulasi


DOM pada halaman web.

Ayo bahas beberapa template dasar direktif disini.

Text content

Alpine membuat mudah untuk mengendalikan teks content dari sebuah


elemen dengan direktif x-text.

<div x-data="{ title: 'Start Here' }">


<h1 x-text="title"></h1>
</div>;

Kini, Alpine telah mengatur teks konten dari <h1> dengan nilai dari title
(“Start Here”). Ketika title berubah, maka content <h1> akan berubah juga.

Seperti semua direktif di dalam Alpine anda dapat menggunakan ekspresi


JavaScript apapun sesuka. Sebagai contoh:

21
<span x-text="1 + 2"></span>;

<span> kini akan berisi penjumlahan dari “1” dan “2”.

Toggling Elements

Toggling elemen adalah kebutuhan umum dalam sebuah halaman dan


aplikasi. Dropdown, modal, dialogs, “show-more”, dan lain-lain adalah
contoh-contoh bagus.

Alpine menawarkan direktif x-show dan x-if untuk toggling pada halaman

x-show

ini adalah komponen toggle sederhana menggunakan x-show.

<div x-data="{ open: false }">


<button @click="open = ! open">Expand</button>

<div x-show="open">
Content...
</div>
</div>

Sekarang semua <div> berisi konten yang akan ditampilkan dan


disembunyikan berdasarkan nilai dari open.

Di belakang layar, Alpine menambahkan CSS Property display: none; ke


elemen ketika itu harusnya disembunyikan.

Ini berfungsi dengan baik pada banyak kasus tapi terkadang anda
mungkin ingin menghapus dan menambahkan elemen dari DOM
seluruhnya. Ini adalah kegunaan x-if

x-if

Ini adalah toggle yang sama seperti sebelumnya tapi kali ini
menggunakan x-if alih-alih x-show.

<div x-data="{ open: false }">


<button @click="open = ! open">Expand</button>

<template x-if="open">
<div>
22
Content...
</div>
</template>
</div>

Perhatikan bahwa x-if harus dideklarasikan pada tag <template>. Ini


dilakukan agar Alpine dapat memanfaatkan perilaku browser (peramban)
yang ada dari elemen <template> dan menggunakannya sebagai sumber
target <div> untuk ditambahkan dan dihapus dari halaman.

Ketika open adalah true, Alpine akan menambahkan <div> ke tag <template>
dan menghapusnya ketika open adalah false

Toggling with translations

Alpine membuatnya sederhana untuk transisi secara mulus antara


“shown” dan “hidden” state menggunakan direktif x-transition.

* x-transition hanya berfungsi dengan x-show, tidak dengan x-if

Ini, lagi, contoh toggle sederhana, tapi kali ini dengan transisi yang telah
diterapkan:

<div x-data="{ open: false }">


<button @click="open = ! open">Expands</button>

<div x-show="open" x-transition>


Content...
</div>
</div>

Ayo perbesar dalam template dengan transisi:

<div x-show="open" x-transition>

x-transition itu sendiri akan menerapkan sensible bawaan transisi (fate


and scale) toggle.

Ada dua cara untuk transisi yang disesuaikan (customize) tersebut:

 Transition Helper
 Transition CSS classes

Mari kita lihat masing-masing pendekatannya:


23
Transition Helper

Katakanlah anda ingin untuk membuat durasi dari transisi lebih lama,
Anda dapat secara manual menentukan durasi menggunakan modifier
.duration seperti berikut:

<div x-show="open" x-transition.duration.500ms>

sekarang transisi akan menjadi 500 milidetik

Jika anda ingin nilai berbeda yang khusus untuk transisi in dan out, anda
dapat menggunakan x-transition:enter dan x-transition:leave:

<div
x-show="open"
x-transition:enter.duration.500ms
x-transition:leave.duration.1000ms
>

Selain itu, anda dapat menambahkan .opacity atau .scale hanya ke


transisi dari properti. Sebagai contoh:

<div x-show="open" x-transition.opacity>

Transition classes

jika anda butuh kontrol yang lebih halus pada awal transisi aplikasi anda,
anda dapat menerapkan CSS khusus pada fase khusus dari transisi
menggunakan syntax berikut (ini contoh menggunakan Tailwind CSS):

<div
x-show="open"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform scale-90"
x-transition:enter-end="opacity-100 transform scale-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100 transform scale-100"
x-transition:leave-end="opacity-0 transform scale-90"
>
...
</div>

24
Binding attributes

Anda dapat menambahkan atribut HTML seperti class, style, disabled,


dan lain-lain ..ke elemen di dalam Alpine menggunakan direktif x-bind.

Ini adalah sebuah contoh yang terikat secara dinamis dari atribut class:

<button
x-data="{ red: false }"
x-bind:class="red ? 'bg-red' : ''"
@click="red = ! red"
>
Toggle Red
</button>

Sebagai jalan pintas, anda dapat meninggalkan x-bind dan menggunakan


penulisan singkat : secara langsung:

<button ... :class="red ? 'bg-red' : ''">

Toggling class on dan off berdasarkan data dalam Alpine merupakan


kebutuhan yang umum. Ini adalah sebuah contoh dari sebuah class
menggunakan binding objek syntax class: (catatan: syntax ini hanya
tersedia untuk atribut class)

<div x-data="{ open: true }">


<span :class="{ 'hidden': ! open }">...</span>
</div>

kini class hidden akan ditambahkan ke elemen jika open bernilai false, dan
dihapus jika open bernilai true.

Looping Elements

Alpine memungkinkan bagian iterasi dari template berdasarkan data


JavaScript menggunakan direktif x-for. Ini adalah contoh sederhananya:

<div x-data="{ statuses: ['open', 'closed', 'archived'] }">


<template x-for="status in statuses">
<div x-text="status"></div>
</template>
</div>;

25
Mirip dengan x-if , x-if harus diterapkan ke tag <template>. Secara internal,
Alpine akan menambahkan konten dari <template> setiap iterasi didalam
perulangan.

Seperti yang dapat Anda lihat variabel status baru dalam scope dari
template berulang.

Inner HTML

Alpine memudahkan untuk mengontrol content HTML dari sebuah elemen


dengan direktif x-html.

<div x-data="{ title: '<h1>Start Here</h1>' }">


<div x-html="title"></div>
</div>;

Sekarang, Alpine dapat mengatur konten teks dari <div> dengan elemen
<h1>Start Here</h1>. Ketika title berubah, maka content <h1> akan berubah
juga.

** hanya gunakan pada konten yang terpercaya dan jangan pernah


gunakan pada konten yang disediakan pengguna rendering html secara
dinamis dari pihak ketiga dapat dengan mudah mengarah kepada
kerentanan XSS

Event
Alpine membuatnya sederhana untuk mendengarkan browser
(peramban) event dan bereaksi pada event tersebut.

listening for simple event

Dengan menggunakan x-on, Anda dapat listen (mendengarkan) untuk


browser event yang di dispatch pada atau didalam elemen.

Ini adalah contoh dasar dari listening untuk klik pada tombol:

<button x-on:click="console.log('clicked')">...</button>;
sebagai sebuah alternatif, anda dapat menggunakan penulisan singkat
event jika anda suka: @. Ini sama seperti contoh sebelumnya tapi
menggunakan syntax penulisan singkat (yang akan kita gunakan untuk
mulai dari sekarang):

<button @click="...">...</button>

26
Sebagai tambahan untuk click, Anda dapat listen untuk browser event
apapun dengan nama. Sebagai contoh: @mouseenter, @keyup, dan lain-
lain...semua adalah syntax (sintaksis) yang valid.

Listening for specific keys

Katakanlah anda ingin mendengarkan key enter untuk ditekan di dalam


elemen <input>. Alpine membuatnya mudah dengan menambahkan
.enter:

<input @keyup.enter="...">
Anda dapat menggabungkan key modifier untuk mendengarkan
kombinasi key seperti menekan enter ketika menahan shift:

<input @keyup.shift.enter="...">

Preventing Default

Ketika reaksi browser event, sering diperlukan “prevent default” (prevent


default yang merupakan event dari browser).

Sebagai contoh, Jika anda ingin mendengarkan (listen) sebuah form


submission tapi mencegah browser dari submitting sebuah form request,
Anda dapat menggunakan .prevent:

<form @submit.prevent="...">...</form>

Anda dapat juga menerapkan .stop untuk mencapai hal yang sama
dengan event.stopPropagation()

Accessing the event object

Terkadang Anda mungkin ingin mengakses objek native browser event


didalam kode anda sendiri. Untuk mempermudahnya, Alpine akses secara
otomatis menyuntikan variabel magic $event

<button @click="$event.target.remove()">Remove Me</button>

Dispatching Custom Event

Sebagai tambahan untuk mendengarkan browser event, anda dapat


dispatch mereka juga. Ini sangat berguna untuk komunikasi dengan

27
komponen Alpine lainnya atau untuk memicu event di dalam tool di luar
dari Alpine itu sendiri.

Alpine mengekpose sebuah magic helper bernama $dispatch untuk ini:

<div @foo="console.log('foo was dispatched')">


<button @click="$dispatch('foo')"></button>
</div>
seperti yang anda dapat lihat, ketika tombol diklik, Alpine akan dispatch
sebuah browser event yang dinamakan “foo”, dan @foo kita mendengarkan
pada <div> akan mengambilnya dan bereaksi padanya.

Listening for event on Windows

Karena event dalam Browser, terkadang berguna untuk mendengarkan


event pada top-level window object.

Ini memungkinkan anda untuk komunikasi di seluruh komponen


sepenuhnya seperti contoh berikut:

<div x-data>
<button @click="$dispatch('foo')"></button>
</div>

<div x-data @foo.window="console.log('foo was dispatched')">...</div>

Pada contoh diatas, jika kita klik tombol dalam komponen pertama, Alpine
akan dispatch event. Karena cara event bekerja di browser. Mereka
“bubble” up melalui parent element kesemua top-level “window”.

Sekarang, karena dalam komponen kedua kita mendengarkan “foo” pada


window (dengan .window), ketika tombol diklik, listener ini akan mengambil
dan log pesan “foo was dispatched”.

Lifecycle
Alpine memiliki beberapa teknik berbeda untuk menyambungkan bagian
berbeda dari siklus hidup. Ayo mulai dengan salah satu yang paling
berguna dan familiar dengan anda:

Element initialization

Lifecycle hook yang sangat berguna di Alpine adalah direktif x-ini.

28
x-ini dapat ditambahkan ke elemen apapun di halaman dan akan
mengeksekusi JavaScript apapun yang anda panggil di dalamnya ketika
Alpine memulai menginisialisasi elemen tersebut.

<button x-init="console.log('Im initing')">

Tambahan ke direktif, Alpine akan secara otomatis memanggil method


init() apapun yang tersimpan pada data objek. Sebagai contoh:

Alpine.data('dropdown', () => ({
init() {
// I get called before the element using this data initializes.
}
})

After a state change

Alpine memungkinkan anda untuk mengeksekusi kode ketika bagian dari


data (state) berubah. Alpine menawarkan dua API yang berbeda untuk
tugas ini: $watch dan x-effect.
$watch

<div x-data="{ open: false }" x-init="$watch('open', value =>


console.log(value))"></div>

seperti yang dapat Anda lihat di atas, $watch memungkinkan anda untuk
hook ke dalam perubahan data menggunakan dot-notation (notasi titik)
key. Ketika bagian data tersebut berubah Alpine akan memanggil
callback yang di oper dan berikannya nilai baru bersama dengan nilai
lama sebelum berubah.
x-effect

x-effect menggunakan mekanisme yang sama di belakang layar seperti


$watch tapi memiliki kegunaan yang berbeda.

Alih-alih menentukan data key mana yang anda ingin pantau, x-effect
akan memanggil kode yang telah disediakan dan secara cerdas melihat
data apapun yang Alpine gunakan di dalamnya. Sekarang yang ketika 1
bagian data berubah. ekspresi x-effect akan dijalankan ulang.

29
Ini adalah kode yang sama dari contoh $watch ditulis ulang menggunakan
x-effect:

<div x-data="{ open: false }" x-effect="console.log(open)"></div>

Sekarang ekspresi ini dipanggil dengan cara yang benar, dan dipanggil
ulang setiap kali open di perbarui.

Dua perilaku utama yang berbeda dengan pendekatan ini adalah:

menyediakan kode yang akan segera dijalankan DAN ketika data berubah
($watch bersifat “malas” tidak akan berjalan sampai data pertama
berubah)

Tidak diketahui tentang nilai sebelumnya, (callback yang disediakan ke


$watc menerima nilai baru DAN nilai lama).

Alpine initialization
alpine:init

Memastikan bagian kode dieksekusi setelah Alpine di muat, tapi SEBELUM


Alpine menginisialisasi dirinya sendiri pada halaman merupakan sebuah
tugas yang diperlukan.

Hook ini menginginkan anda untuk mendaftarkan custom data, direktif,


magic dan lian-lain, sebelum Alpine melakukan sesuatu di halaman.

Anda dapat menghubungkan (hook)ini di siklus hidup dengan


mendengarkan sebuah event yang Alpine dispatch bernama alpine:init

document.addEventListener('alpine:init', () => {

Alpine.data(...)

})
alpine:initialized

Alpine juga menawarkan sebuah hook yang dapat anda gunakan untuk
mengeksekusi kode setelah Alpine selesai melakukan inisialisasi yang
bernama alpine:initialized:

document.addEventListener("alpine:initialized", () => {
//
});

30
Directives
x-data
Apapun di Alpine dimulai dengan direktif x-data

x-data mendefinisikan sebuah chunk dari HTML sebagai komponen Alpine


dan menyediakan data reaktif untuk referensi komponen tersebut.

Ini adalah sebuah contoh komponen dropdown:

<div x-data="{ open: false }">


<button @click="open = ! open">Toggle Content</button>

<div x-show="open">
Content...
</div>
</div>

jangan khawatir tentang diaktif lain pada contoh ini(@click dan x-show ),
kita akan membahasnya sebentar lagi. Sekarang, ayo fokus pada x-data

Scope

properti yang didefinisikan dalam sebuah directive x-data tersedia ke


semua elemen children. Meskipun satu dengan yang lain, komponen x-
data bersarang.

Sebagai contoh:

<div x-data="{ foo: 'bar' }">


<span x-text="foo"><!-- Will output: "bar" --></span>

<div x-data="{ bar: 'baz' }">


<span x-text="foo"><!-- Will output: "bar" --></span>

<div x-data="{ foo: 'bob' }">


<span x-text="foo"><!-- Will output: "bob" --></span>
</div>
</div>
</div>

31
Methods

karena x-data dievaluasi sebagai sebuah objek normal JavaScript, sebagai


tambahan ke state, Anda dapat menyimpan method dan event getters.

Sebagai contoh, Ayo ekstrak perilaku “Toggle Content” ke dalam sebuah


methode x-data.

<div x-data="{ open: false, toggle() { this.open = ! this.open } }">


<button @click="toggle()">Toggle Content</button>

<div x-show="open">
Content...
</div>
</div>
Perhatikan method toggle() { this.open = ! this.open } yang ditambahkan
pada x-data. Method ini sekarang dapat dipanggil dari manapun di dalam
komponen.

Anda juga memperhatikan penggunaan dari this. untuk mengakses pada


objek nya sendiri. Ini karena Alpine mengevaluasi data objek ini seperti
data objek standard JavaScript apapun dengan context this

Jika Anda suka, Anda dapat membiarkan method toggle sepenuhnya


tanpa tanda kurung. Sebagai contoh:

<!-- Before -->


<button @click="toggle()">...</button>

<!-- After -->


<button @click="toggle">...</button>
Getters

getter JavaScript berguna ketika sebuah method hanya memiliki satu


tujuan yaitu mengembalikan data berdasarkan state.

pikirkan mereka seperti “properti yang dihitung” (meskipun mereka tidak


cached seperti properti yang dihitung dimiliki Vue.

ayo refactor komponen kita menggunakan sebuah getter bernama isOpen


alih-alih mengakses open secara langsung.
<div x-data="{
open: false,
get isOpen() { return this.open },
toggle() { this.open = ! this.open },

32
}">
<button @click="toggle()">Toggle Content</button>

<div x-show="isOpen">
Content...
</div>
</div>

perhatikan kini “content” bergantung pada getter isOpen alih-alih pada


properti open secara langsung.

Pada kasus ini ini ada keuntungan tak terlihat. Pada beberapa
kasus, getter berguna untuk menyiasati akan syntax yang lebih ekspresif
di komponen anda.

Data-less components

Kadang-kadang, anda ingin membuat sebuah komponen Alpine, tapi


anda tidak membutuhkan data apapun.

Pada kasus ini ini anda dapat selalu mengoper sebuah objek kosong.
<div x-data="{}">

Meskipun, jika anda ingin, anda dapat menghapus nilai atribut seluruhnya
jika Itu tampak lebih bagus untuk anda.
<div x-data></div>

Single-element components

Terkadang Anda mungkin hanya memiliki sebuah elemen tunggal berikut:


<div x-data="{ open: true }">
<button @click="open = false" x-show="open">Hide Me</button>
</div>
pada kasus ini, anda dapat mendeklarasikan x-data secara langsung pada
elemen tunggal.
<button x-data="{ open: true }" @click="open = false" x-show="open">
Hide Me
</button>

33
Re-useable data

Jika anda mendapati diri Anda menduplikasi konten dari x-data atau anda
mendapati suntax yang bertele-tele, Anda dapat mengekstrak x-data objek
ke sebuah komponen yang terdedikasi menggunakan Alpine.data

berikut ini contoh cepatnya:


<div x-data="dropdown">
<button @click="toggle">Toggle Content</button>

<div x-show="open">
Content...
</div>
</div>

<script>
document.addEventListener('alpine:init', () => {
Alpine.data('dropdown', () => ({
open: false,

toggle() {
this.open = ! this.open
},
}))
})
</script>

x-init
Direktif x-init yang memungkinkan anda untuk menghubungkan (hook) ke
fase inisialisasi dari elemen manapun di Alpine.

<div x-init="console.log('I\'m being initialized!')"></div>;


pada contoh diatas, "I'm being initialized!" akan muncul di console
sebelum membuat pembaruan pembaruan di DOM.

Pertimbangkan contoh lain ketika x-init digunakan untuk mengambil


beberapa JSON dan menyimpannya di dalam x-data sebelum komponen
diproses.
<div
x-data="{ posts: [] }"
x-init="posts = await (await fetch('/posts')).json()"
>
...
</div>;

34
$nextTick

Terkadang, Anda ingin menunggu sampai Alpine selesai rendering


sepenuhnya untuk mengeksekusi beberapa kode.

Ini akan seperti useEffect(..., []) di react, atau moun di Vue

dengan menggunakan internal magic $nextTick Alpine Anda dapat


membuat ini terjadi.
<div x-init="$nextTick(() => { ... })"></div>;

Standalone x-init

Anda dapat menambahkan x-init ke elemen manapun baik didalam


maupun diluar sebuah blog HTML sebagai contoh:
<div x-data>
<span x-init="console.log('I can initialize')"></span>
</div>

<span x-init="console.log('I can initialize too')"></span>

Auto-evaluate init() method

jika objek x-data dari sebuah komponen berisi sebuah


method init(). Method akan dipanggil secara otomatis. Sebagai contoh:
<div
x-data="{
init() {
console.log('I am called automatically')
}
}"
>
...
</div>;

Ini juga kasus untuk Komponen yang telah didaftarkan menggunakan


syntax Alpine.data()
Alpine.data("dropdown", () => ({
init() {

35
console.log(
'I will get evaluated when initializing each "dropdown" component.'
);
},
}));

x-show
x-show merupakan salah satu direktif yang berguna dan kuat di Alpine. x-
show menyediakan sebuah cara ekspresif untuk menampilkan dan
menyembunyikan DOM element

Ini adalah sebuah contoh dari komponen dropdown sederhana


menggunakan x-show.
<div x-data="{ open: false }">
<button x-on:click="open = ! open">Toggle Dropdown</button>

<div x-show="open">Dropdown Contents...</div>


</div>;

ketika tombol “Toggle Dropdown” diklik, dropdown akan tampil dan


disembunyikan.

*jika “defaul” state sebuah x-show pada halaman muat berniali “false”,
anda mungkin ingin menggunakan x-cloak pada halaman untuk
menghindari “page flicker” (efek yang terjadi ketika peramban render
konten anda sebelum Alpine selesai inisialisasi dan menyembunyikannya)

With translation

Jika anda ingin menerapkan transisi yang halus ke perilaku x-show, anda
dapat menggunakan x-show dalam konjungsi dengan x-transition . ini
adalah sebuah contoh cepat dari komponen sama seperti diatas hanya
berbeda dengan diterapkannya transition.
<div x-data="{ open: false }">
<button x-on:click="open = ! open">Toggle Dropdown</button>

<div x-show="open" x-transition>


Dropdown Contents...
</div>
</div>;

36
x-bind
x-bind memungkinkan anda untuk mengatur atribut HTML pada elemen
berdasarkan hasil dari ekspresi JavaScript.

Sebagai contoh, Ini adalah sebuah komponen yang akan kita gunakan x-
bind untuk mengatur placeholder nilai dari sebuah input.

<div x-data="{ placeholder: 'Type here...' }">


<input type="text" x-bind:placeholder="placeholder">
</div>

Shorthand syntax

jika x-bind: menurut anda terlalu bertele-tele, anda dapat menggunakan


penulisan singkat : . Sebagai contoh, ini merupakan elemen input yang
sama seperti diatas tapi telah di refactor menggunakan syntax yang lebih
singkat.
<input type="text" :placeholder="placeholder"></input>
Binding classes

x-bind sering berguna untuk pengaturan class khusus pada sebuah


elemen berdasarkan state Alpine anda.

Ini adalah sebuah contoh dari dropdown tonggle sederhana, tapi alih-alih
menggunakan x-show kita akan menggunakan sebuah class “hidden” untuk
toggle elemennya.
<div x-data="{ open: false }">
<button x-on:click="open = ! open">Toggle Dropdown</button>

<div :class="open ? '' : 'hidden'">


Dropdown Contents...
</div>
</div>
Sekarang, ketika open bernilai false, class “hidden” akan ditambahkan ke
dropdown

Shorthand Conditional

pada kasus seperti ini jika anda lebih suka syntax yang tidak bertele-tele
anda dapat menggunakan short-circuit evaluasinya JavaScript alih-alih
standar conditional:
<div :class="show ? '' : 'hidden'">
<!-- Is equivalent to: -->

37
<div :class="show || 'hidden'"></div>
Sebaliknya juga tersedia untuk anda, Bukannya menggunakan open kita
menggunakan sebuah variabel dengan nilai kebalikannya closed
<div :class="closed ? 'hidden' : ''">
<!-- Is equivalent to: -->
<div :class="closed && 'hidden'"></div>

Class Object Syntax

Alpine menawarkan sebuah syntax tambahan untuk toggling class jika


anda suka. Dengan mengoper sebuah objek JavaScript di mana class
adalah key dan boolean adalah nilai, Alpine akan mengetahui class mana
yang menerapkan dan mana yang menghapus. Sebagai contoh:
<div :class="{ 'hidden': ! show }"></div>

Teknik ini menawarkan sebuah keuntungan unik dari method lainnya.


Ketika menggunakan syntax-object Alpine TIDAK menjaga class asli yang
yang diterapkan ke elemen atribut class .

Sebagai contoh, Jika anda ingin menerapkan class “hidden” ke sebuah


elemen sebelum Alpine memuat DAN menggunakan Alpine untuk toggle
yang telah ada. Anda mencapai perilaku tersebut menggunakan objek-
syntax.
<div class="hidden" :class="{ 'hidden': ! show }"></div>
Mmungkin ini membingungkan anda, ayo gali lebih dalam bagaimana
Alpine menangani x-bind:class secara berbeda daripada atribut yang lain

Special behavior

x-bind:class berperilaku secara berbeda dari atribut yang lain di belakang


layar

Perhatikan contoh berikut


<div class="opacity-50" :class="hide && 'hidden'">

Jika “class” ada atribut lainnya, :class akan menimpa atribut kelas yang
ada, karena opacity-50 akan ditimpa baik oleh hidden atau ''.

38
Meskipun Alpine memperlakukan class binding secara berbeda, Alpine
cukup pintar untuk mempertahankan kelas yang ada pada sebuah
elemen.

Sebagai contoh jika hide bernilai true, contoh diatas akan menghasilkan
DOM elemen seperti berikut:

div class="opacity-50 hidden">

jika hide bernilai true, elemen akan tampak seperti ini:

<div class="opacity-50"></div>

perilaku ini ini sebaiknya tak terlihat dan dan intuitif untuk kebanyakan
pengguna tapi pantas untuk di disebut secara eksplisit untuk menjawab
pertanyaan developer atau kasus-kasus khusus yang mungkin muncul.

Binding Style

Mirip dengan syntax khusus untuk dinding kelas dengan objek JavaScript
Alpine juga menawarkan sebuah syntax berbasis objek untuk binding
atribut style

Seperti class objek, syntax ini sepenuhnya opsional. Hanya gunakan syntax
ini jika memberi keuntungan bagi anda.

<div :style="{ color: 'red', display: 'flex' }">

<!-- Will render: -->


<div style="color: red; display: flex;" ...></div>

Conditional Inline style memungkinkan penggunaan ekspresi seperti


dengan x-bind:class. short circuit operator juga dapat digunakan di sini
dengan menggunakan sebuah objek style sebagai operan kedua.

<div x-bind:style="true && { color: 'red' }">

<!-- Will render: -->


<div style="color: red;"></div>

39
salah satu keuntungan dari pendekatan ini adalah mampu untuk
mencampur dengan style yang sudah ada pada sebuah elemen:

<div style="padding: 1rem;" :style="{ color: 'red', display: 'flex' }">

<!-- Will render: -->


<div style="padding: 1rem; color: red; display: flex;" ...></div>

Dan seperti kebanyakan ekspresi di Alpine Anda dapat juga selalu


menggunakan hasil dari sebuah ekspresi JavaScript sebagai referensi:

div x-data="{ styles: { color: 'red', display: 'flex' }}">


<div :style="styles">
</div>

<!-- Will render: -->


<div ...>
<div style="color: red; display: flex;" ...>
</div>

Binding Alpine Directives Directly

x-bind memungkinkan anda untuk mengikat sebuah objek dari directive


ada dan dan atribut yang berbeda ke sebuah elemen.

Objek dapat berisi apapun yang yang normalnya ditulis sebagai sebuah
nama atribut di Alpine. Ini masuk directive Alpine dan modifier, tapi juga
HTML atribut biasa nilai objek bisa berupa string polos atau bisa juga
sebuah directif dinamis, atau callback yang dievaluasi oleh Alpine.

<div x-data="dropdown()">
<button x-bind="trigger">Open Dropdown</button>

<span x-bind="dialogue">Dropdown Contents</span>


</div>

<script>
document.addEventListener('alpine:init', () => {
Alpine.data('dropdown', () => ({
open: false,

trigger: {
['x-ref']: 'trigger',
['@click']() {
this.open = true

40
},
},

dialogue: {
['x-show']() {
return this.open
},
['@click.outside']() {
this.open = false
},
},
}))
})
</script>

ini ada beberapa peringatan penggunaan x-bind:

**ketika direktif menjadi “bound” atau “applied” x-for , Anda harus


mengembalikan sebuah normal ekspresi string dari callback. Sebagai
contoh ['x-for']() { return 'item in items' }

x-on
x-on memungkinkan anda dengan mudah menjalankan kode pada
dispatch DOM event

ini merupakan sebuah contoh tombol sederhana yang menampilkan


sebuah peringatan (alert) ketika di klik.

<button x-on:click="alert('Hello World!')">Say Hi</button>;

* x-on hanya dapat mendengar sebuah event dengan nama lower case,
sebagai atribut HTML yang yang case-insensitive. Penulisan x-on:CLICK
akan mendengar (listen)pada sebuah event bernama click. Jika anda
butuh untuk mendengar ke sebuah event custom dengan nama
camelCase anda dapat menggunakan Helper .camel untuk bekerja di
sekitar batasan ini. Sebagai alternatif anda dapat menggunakan x-bind
untuk disisipkan pada direktif x-on sebuah elemen ke dalam kode
JavaScript (di mana kasus akan dipertahankan)

41
Shorthand Syntax

jika x-on: terlalu bertele-tele menurut anda, anda dapat menggunakan


penulisan singkat syntax @.

Ini merupakan komponen yang sama dengan komponen di atas tapi


menggunakan kan tak yang lebih singkat:

<button @click="alert('Hello World!')">Say Hi</button>

The Event Object

Jika Anda berharap mengakses objek event native JavaScript dari ekspresi
anda, anda dapat menggunakan properti magic $event milik Alpine.

<button @click="alert($event.target.getAttribute('message'))" message="Hello


World">Say Hi</button>
Sebagai tambahan, Alpine juga mengoper event object ke method
apapun yang telah di referensi tanpa apa tanda kurung di belakang.
Sebagai contoh:

<button @click="handleClick">...</button>

<script>
function handleClick(e) {
// Now you can access the event object (e) directly
}
</script>

keyboard event

Alpine memudahkan untuk listen ke keydown dan keyupevent pada key


khusus.

Ini adalah sebuah contoh dari mendengarkan key Enter di dalam sebuah
input element
<input type="text" @keyup.enter="alert('Submitted!')">
Anda dapat juga merantai/menyambungkan (chain) modifier ini untuk
mencapai listener yang lebih kompleks.

Ini adalah sebuah listener yang berjalan ketika key Shift ditahan dan
Enter ditekan tapi tidak ketika Enter ditekan sendiri.

<input type="text" @keyup.shift.enter="alert('Submitted!')">

42
Anda dapat secara langsung menggunakan nama key apapun yang
valid melalui KeyboardEvent.key sebagai modifier dengan mengkonversinya
ke kebab-case.
<input type="text" @keyup.page-down="alert('Submitted!')">
untuk memudahkan referensi ini ada sebuah list key yang umum yang
mungkin anda ingin gunakan.

Modifier Keyboard Key

.shift Shift

.enter Enter

.space Space

.ctrl Ctrl

.cmd Cmd

.meta Cmd on Mac, Ctrl on Windows

.alt Alt

.up .down .left .right Up/Down/Left/Right arrows

.escape Escape

.tab Tab

.caps-lock Caps Lock

.equal Equal, =

.period Period, .

.slash Foward Slash, /

Custom Event

Alpine event listener merupakan sebuah pembungkus untuk DOM event


listener native, karena itu, mereka dapat listen ke event DOM MANA PUN,
termasuk event custom.

43
Ini adalah sebuah contoh komponen yang dispatch sebuah custom DOM
event dan listen juga.
<div x-data @foo="alert('Button Was Clicked!')">
<button @click="$event.target.dispatchEvent(new CustomEvent('foo', {
bubbles: true }))">...</button>
</div>

ketika tombol telah diklik, @foo listener akan dipanggil.

Karena API .dispatchEvent terlalu bertele-tele, Alpine menawarkan sebuah


Helper $dispatch untuk menyederhanakannya.

Ini adalah komponen yang sama yang ditulis ulang dengan properti
magic $dispatch.
<div x-data @foo="alert('Button Was Clicked!')">
<button @click="$dispatch('foo')">...</button>
</div>

Modifier

Alpine menawarkan sejumlah directive modifier untuk custom perilaku dari


event listener anda.

.prevent

.prevent sama dengan memanggil .preventDefault() didalam sebuah


listener pada browser event object.
<form @submit.prevent="console.log('submitted')" action="/foo">
<button>Submit</button>
</form>

.stop

Mirip dengan.prevent, .stop sama dengan memanggil .stopPropagation()


didalam sebuah listener pada browser event object.
<div @click="console.log('I will not get logged')">
<button @click.stop>Click Me</button>
</div>

Pada contoh diatas, mengklik tombol TIDAK AKAN menampilkan pesan. Ini
karena kita menghentikan propagation dari event segera dan tidak

44
mengizinkannya untuk “bubble” (menggembung) ke atas ke <div> dengan
listener @click padanya.

.outside

.outside merupakan sebuah helper untuk mendengarkan ke sebuah klik di


luar elemennya yang disisipkan. Ini adalah sebuah komponen dropdown
sederhana untuk demonstrasi:
<div x-data="{ open: false }">
<button @click="open = ! open">Toggle</button>

<div x-show="open" @click.outside="open = false">


Contents...
</div>
</div>

pada contoh diatas, setelah menampilkan konten dropdown dengan


mengklik tombol “Toggle”, Anda dapat menutup dropdown dengan
mengklik di manapun dihalaman di luar konten.

Ini karena .outside mendengarkan klik yang tidak berasal dari elemen
yang telah didaftarkan.

* perlu dicatat bahwa ekspresi .outside hanya dievaluasi ketika elemen


telah didaftarkan pada ada halaman yang tampak. Jika tidak, akan
menjadi kondisi balapan yang buruk ketika mengklik tombol “Toggle” juga
akan memicu @click.outside ketika tidak terlihat.

.window

ketika .window modifier hadir, Alpine akan mendaftarkan event listener


pada root window object pada halaman alih-alih pada elemen nya sendiri.
<div @keyup.escape.window="...">...</div>
Potongan kode di atas akan listen untuk key “escape” ditekan DIMANAPUN
di halaman.

Penambahan .window ke listener sangat yang berguna untuk semacam


kasus dimana sebuah bagian dari markup anda berkaitan dengan event
yang mengambil tempat di sulurh halaman.

.document

45
.document bekerja mirip dengan .window hanya .document mendaftarkan
listener pada standar pada document global dokumen, alih-alih pada
document global.

.once

Dengan menambahkan .once ke sebuah listener, Anda memastikan bahwa


handler hanya dipanggil SEKALI.
<button @click.once="console.log('I will only log once')">...</button>

.debounce

Terkadang sangat berguna untuk “membangkitkan kembali” (debounce)


sebuah event handler jadi event hanya dipanggil setelah waktu periode
tertentu tidak aktif (250 milidetik secara default).

Sebagai contoh, jika anda memiliki sebuah kolom pencarian yang yang
memicu Network request ketika pengguna mengetik di kolom search
tersebut, penambahan sebuah dipotong akan mencegah Network
request dijalankan setiap kali penekanan tombol (keystroke).
<input @input.debounce="fetchResults">

Sekarang, alih-alih memanggil fetchResults setiap kali keystroke,


fetchResults hanya dipanggil setelah 250 milidetik dari saat setelah
keystroke.

Jika Anda berharap lebih panjang atau lebih pendek untuk waktu
“debounce”, Anda dapat melakukannya dengan menambahkan durasi
setelah modifier .debounce:
<input @input.debounce.500ms="fetchResults">

Sekarang, fetchResults hanya dipanggil setelah 500 milidetik dari tidak


aktif.

.throttle

.throttle mirip dengan .debounce kecuali .throttle akan membebaskan


sebuah handler yang dipanggil setiap 250 milidetik alih-alih menundanya
tanpa batas waktu.

46
Ini sangat berguna pada kasus dimana mungkin event dijalankan
berulang-ulang dan dan berkepanjangan dan penggunaan .debounce dan
tidak berfungsi karena anda masih ingin menghandle event yang sangat
sering.

Sebagai contoh:

<div @scroll.window.throttle="handleScroll">...</div>
Contoh di atas merupakan contoh yang bagus dari pelambatan
(throttling). Tanpa .throttle, method handleScroll dijalankan ratusan kali
ketika pengguna menggulir halaman kebawah. Ini dapat membuat
website menjadi lambat. Dengan menambahkan .throttle, kita
memastikan bahwa handleScroll hanya dapat dipanggil setiap 250
milidetik.

Sama seperti .debounce, anda dapat menambah sebuah durasi custom


pada event yang diperlambat:

<div @scroll.window.throttle.750ms="handleScroll">...</div>
Sekarang, handleScroll hanya dipanggil setiap 750 milidetik.

.self

Dengan menambahkan .self ke sebuah event listener, anda pastikan


bahwa event dari elemen yang telah di deklarasikan bukan dari child
elemen.

<button @click.self="handleClick">
Click Me

<img src="...">
</button>

Pada contoh diatas, kita memiliki sebuah tag <img> di dalam tag <button>.
Normalnya, klik apapun yang berasal dari elemen <button> (seperti pada
<img> contohnya), akan diambil oleh listener @click pada tombol.

.camel

<div @custom-event.camel="handleCustomEvent">
...
</div>

47
Terkadang Anda mungkin ingin untuk listen ke event camelCase seperti
customEvent pada contoh kita. Karena camelCase di dalam atribut html
tidak didukung, penambahan modifier .camel diperlukan untuk Alpine ke
nama event camelCase secara internal.

Dengan menambahkan .camel pada contoh diatas, Alpine kita listening


untuk customEvent alih-alih custom-event

.dot

<div @custom-event.dot="handleCustomEvent">
...
</div>

Mirip dengan modifier .camelCase ada mungkin situasi dimana anda ingin
listen ke event yang yang memiliki titik dinamanya (sperti custom.event).
Karena dengan nama event dipakai oleh Alpine anda butuh menulis
dengan tanda hubung dan menambahkan modifier .dot

Pada contoh kode di atas custom-event.dot akan sesuai dengan nama


custom.event

.passive

Peramban mengoptimasi scrolling pada halaman menjadi cepat dan


mulus meski ketika JavaScript dieksekusi di halaman. Namun, sentuhan
yang diterapkan tidak benar dan roda listen dapat memblok optimasi ini
karena menyebabkan performa website yang buruk.

Jika anda ada mendengarkan event touch, penting untuk menambahkan


.passive ke listener anda agar tidak memblokir performa scroll.

<div @touchstart.passive="...">...</div>

x-text
x-text mengatur konten teks dari sebuah elemen yang merupakan hasil
dari ekspresi.

Ini adalah contoh dasar dari penggunaan x-text untuk menampilkan


username pengguna.

48
<div x-data="{ username: 'calebporzio' }">
Username: <strong x-text="username"></strong>
</div>;

sekarang tag <strong> di dalam teks konten akan diset ke “calebporzio”.

x-html
x-html mengatur property “innerHTML” dari sebuah elemen ke hasil yang
diberikan ekspresi.

**hanya gunakan sumber konten terpercaya dan jangan pernah gunakan


konten yang disediakan pengguna. Rendering HTML secara dinamis dari
pihak ketiga dapat dengan mudah menuju kerentanan XSS.

Ini adalah sebuah contoh dasar dari penggunaan x-html untuk


menampilkan username sebuah seorang pengguna.

<div x-data="{ username: '<strong>calebporzio</strong>' }">


Username: <span x-html="username"></span>
</div>;
Sekarang tag <span> innerHTML akan diset ke “calebporzio”

x-model

x-model memungkinkan anda mengikat nilai dari sebuah elemen Input ke


data Alpine.

Ini adalah sebuah contoh sederhana dari penggunaan x-model yang


mengikat nilai dari kolom teks ke bagian data di dalam Alpine.

<div x-data="{ message: '' }">


<input type="text" x-model="message">

<span x-text="message">
</div>
Sekarang, saat pengguna mengetik di dalam kolom teks, message akan
tercermini dalam <span>.

x-model merupakan “two-way bound”, artinya “sets” dan “gets”. Sebagai


tambahan untuk mengubah data Jika data tersebut berubah elemen
akan mencerminkan perubahan tersebut.

49
Anda dapat menggunakan contoh terompah di atas tapi kali ini, kita
menambah sebuah tombol untuk mengubah nilai dari property message.

<div x-data="{ message: '' }">


<input type="text" x-model="message">

<button x-on:click="message = 'changed'">Change Message</button>


</div>
Sekarang ketika button di klik, nilai elemen input akan secara cara instan
barui ke “changed”.

x-model bekerja dengan mengikuti input element:

<input type="text">

<textarea>

<input type="checkbox">

<input type="radio">

<select>

Text inputs

<input type="text" x-model="message">

<span x-text="message"></span>

Textarea inputs

<textarea x-model="message"></textarea>

<span x-text="message"></span>

Checkbox Inputs

single checkbox with boolean

<input type="checkbox" id="checkbox" x-model="show">

<label for="checkbox" x-text="show"></label>

multiple checkboxes bound to array

<input type="checkbox" value="red" x-model="colors">


<input type="checkbox" value="orange" x-model="colors">
50
<input type="checkbox" value="yellow" x-model="colors">

Colors: <span x-text="colors"></span>

Radio Inputs

<input type="radio" value="yes" x-model="answer">


<input type="radio" value="no" x-model="answer">

Answer: <span x-text="answer"></span>

Select Inputs

single select

<select x-model="color">
<option>Red</option>
<option>Orange</option>
<option>Yellow</option>
</select>;

Color: <span x-text="color"></span>;

Single select with placeholder

<select x-model="color">
<option value="" disabled>
Select A Color
</option>
<option>Red</option>
<option>Orange</option>
<option>Yellow</option>
</select>;

Color: <span x-text="color"></span>;

Multiple Select

<select x-model="color" multiple>


<option>Red</option>
<option>Orange</option>
<option>Yellow</option>
</select>;

51
Colors: <span x-text="color"></span>;

Dynamically populate select options

<select x-model="color">
<template x-for="color in ['Red', 'Orange', 'Yellow']">
<option x-text="color"></option>
</template>
</select>;

Color: <span x-text="color"></span>;

Modifier
.lazy

Pada text input, secara default, x-model update properti setiap kali
keystroke. Dengan penambahan modifier .lazy , anda dapat memaksa
sebuah input x-model untuk hanya update properti ketika fokus pergi dari
input element.

Ini berguna untuk real-time form-validation ketika anda mungkin tidak


ingin menampilkan sebuah validasi error input sampai user “tabs” jauh
dari kolom.

<input type="text" x-model.lazy="username">


<span x-show="username.length > 20">The username is too long.</span>
.number

Secara bawaan, data apapun yang tersimpan di dalam sebuah properti


melalui x-model disimpan sebagai string. Untuk memaksa Alpine
menyimpan nilai sebagai sebuah number JavaScript, tambahkan modifier
.number.

<input type="text" x-model.number="age">


<span x-text="typeof age"></span>
.debounce

Dengan menambahkan .debounce ke x-model, Anda dapat dengan mudah


debouce updating dari bound input.

52
Ini berguna seperti ketika kolom pencarian real-time yang mengambil
data baru dari server setiap kali property search berubah.

<input type="text" x-model.debounce="search"></input>


waktu debounce default di 250 milidetik, anda dapat dengan mudah
mengubahnya dengan menambahkan modifier waktu seperti berikut.

<input type="text" x-model.debounce.500ms="search">

.throttle

Mirip dengan .debounce anda dapat membatasi properti update terpicu


oleh x-model ke hanya update pada interval yang spesifik.

Interval default throttle adalah 250 milidetik, Anda dapat dengan mudah
mengubahnya dengan menambahkan sebuah modifier waktu.

<input type="text" x-model.throttle.500ms="search">

Programmatic access

Alpine mengekspos utility di belakang layar untuk properti getting dan


setting yang terikat dengan x-model. Ini berguna ketika utilitas Alpine yang
kompleks yang mungkin anda ingin timpa dengan perilaku default x-
model, atau Instance ketika anda ingin mengizinkan x-model pada sebuah
elemen non-input.

Anda dapat akses ini melalui sebuah properti bernama _x_model pada x-
model elemen. _x_model memiliki 2 method get dan set yang terikat dengan
property:

el._x_model.get() (mengembalikan (return) nilai dari property yang terikat)

el._x_model.set() (mengatur nilai dari property yang terikat)

<div x-data="{ username: 'calebporzio' }">


<div x-ref="div" x-model="username"></div>

<button @click="$refs.div._x_model.set('phantomatrix')">
Change username to: 'phantomatrix'
</button>

<span x-text="$refs.div._x_model.get()"></span>
</div>

53
x-modelable
x-modelable memungkinkan anda untuk mengekspos properti Alpine
apapun sebagai target dari direktif x-model.

Ini adalah sebuah contoh sederhana dari penggunaan x-modelable untuk


mengekspos sebuah variabel yang mengikat dengan x-model.

<div x-data="{ number: 5 }">


<div x-data="{ count: 0 }" x-modelable="count" x-model="number">
<button @click="count++">Increment</button>
</div>

Number: <span x-text="number"></span>


</div>

Seperti yang dapat Anda lihat properti dengan scope luar bernama
“number” sekarang terikat ke properti dalam bernama “count”.

Secara khusus fitur ini digunakan dalam konjungsi dengan backend


templating framework seperti Laravel Blade. Fitur ini berguna untuk
abstraksi komponen Alpine kedalam template backend dan mengekspos
ke sisi luar melalui x-model seolah-olah itu adalah inputan asli.

x-for
Direktif x-for Alpine memungkinkan anda untuk membuat DOM element
dengan iterasi melalui sebuah list. Ini adalah contoh sederhana dari
penggunaan directive Alpine x-for untuk membuat sebuah list dari color
(warna) berdasarkan sebuah array.

/<ul x-data="{ colors: ['Red', 'Orange', 'Yellow'] }">


<template x-for="color in colors">
<li x-text="color"></li>
</template>
</ul>;

Ada dua aturan yang perlu diperhatikan tentang x-for:

 x-for HARUS dideklarasikan pada sebuah elemen <template>

54
 <template> tersebut HARUS hanya memiliki satu root element

Keys

Keys penting untuk menentukan keys unik untuk setiap iterasi x-for jika
anda akan mengurutkan ulang item. Dengan key dinamis, Alpine mungkin
kesulitan melacak apa yang diurutkan ulang dan akan berdampak pada
ada efek samping yang aneh.

<ul x-data="{ colors: [


{ id: 1, label: 'Red' },
{ id: 2, label: 'Orange' },
{ id: 3, label: 'Yellow' },
]}">
<template x-for="color in colors" :key="color.id">
<li x-text="color.label"></li>
</template>
</ul>

Sekarang jika color ditambahkan, dihapus, dan diurutkan ulang, atau “id”
mereka berubah, Alpine akan menjaga atau menghancurkan elemen <li>
yang sesuai.

Assessing indexes

Jika anda ada perlu akses indeks dari setiap item dalam iterasi, Anda
dapat melakukannya menggunakan sintaks ([item], [index]) in [items]:

<ul x-data="{ colors: ['Red', 'Orange', 'Yellow'] }">


<template x-for="(color, index) in colors">
<li>
<span x-text="index + ': '"></span>
<span x-text="color"></span>
</li>
</template>
</ul>;

Anda dapat juga mengakses index didalam sebuah ekspresi :key dinamis.

<template x-for="(color, index) in colors" :key="index"></template>

55
Iterating over a range

Jika anda butuh loop sejumlah n kali, daripada pengulangan


menggunakan array, Alpine menawarkan syntax pendek

<ul>
<template x-for="i in 10">
<li x-text="i"></li>
</template>
</ul>;

i pada kasus ini dapat bernama apapun sesuka anda.

x-transition
Alpine menyediakan sebuah utility transisi yang kokoh. Dengan beberapa
direktif x-transition, Anda dapat membuat transisi yang mulus ketika
sebuah elemen ditampilkan atau disembunyikan.

Ada dua cara utama untuk menangani transisi di Alpine:

 The Transition Helper


 Applying CSS Classes

The Transition Helper

Cara termudah untuk mencapai sebuah transisi menggunakan Alpin


dengan menambahkan x-transition ke sebuah elemen dengan x-show
dalamnya. Sebagai contoh:

<div x-data="{ open: false }">


<button @click="open = ! open">Toggle</button>

<span x-show="open" x-transition>


Hello 👋
</span>
</div>

Seperti yang dapat Anda lihat, secara bawaan, x-transition menerapkan


transisi bawaan yang menyenangkan untuk memudar (fade) dan
membesar (scale) saat elemen muncul.

56
Anda dapat menimpa default ini dengan menambahkan modifier ke x-
transition .Ayo kita lihat modifier tersebut.

Customizing duration

Awalnya, durasi diatur menjadi 150 milidetik ketika memasuki (entering)


dan 75 milidetik ketika meninggalkan (leaving).

Anda dapat melakukan konfigurasi durasi yang anda ingin untuk sebuah
tradisi dengan modifier .duration

<div ... x-transition.duration.500ms>

<div> di atas akan bertransisi selama 500 milidetik ketika entering, dan 500
milidetik ketika leaving.

Jika anda ingin menyesuaikan (custom) durasi khususnya untuk entering


dan leaving, anda dapat melakukannya seperti berikut:

<div ...
x-transition:enter.duration.500ms
x-transition:leave.duration.400ms
>

Customizing Delay

Anda dapat menunda sebuah transisi menggunakan modifier .delay:

<div ... x-transition.delay.50ms>

Contoh diatas menunda transisi, in dan out dari element selama 50


milidetik.

Customizing opacity.

Secara bawaan, x-transition Alpine diterapkan baik di skala dan opacity


untuk mendapat efek "memudar".

Jika anda berharap untuk hanya menerapkan transisi opacity (tanpa


skala), anda dapat melakukannya dengan cara:

<div ... x-transition.opacity>

57
Customizing scale

Mirip dengan modifier .opacity, anda dapat melakukan konfigurasi x-


transition ke HANYA skala saja (dan tidak pada transisi opaticy juga).

<div ... x-transition.scale>

Modifier .scale juga menawarkan kemampuan untuk mengkonfirgurasi


nilai skala DAN nilai asli:

<div ... x-transition.scale.80>

Potongan kode diatas akan mengskala element keatas dan kebawah


sebanyak 80%.

Lagi, anda mungkin menyesuaikan nilai secara terpisah untuk transisi


enter dan leaving:

<div ...
x-transition:enter.scale.80
x-transition:leave.scale.90
>

untuk meng-custom skala transisi asli, anda dapat menggunakan


modifier .origin:

<div ... x-transition.scale.origin.top></div>


Sekarang skala diterapkan menggunakan element teratas sebagai asal,
alih-alih tengah (center) secara bawaan.

Seperti yang telah anda duga, nilai yang mungkin untuk penyesuaian ini
adalah top, bottom, left, dan right.

Jika anda berharap, anda juga dapat mengkombinasikan 2 nilai asal.


Sebagai contoh, jika anda ingin asal skala menjadi "top right", anda dapat
menggunakan .origin.top.right sebagai modifier.

Applying CSS classes

Untuk kendali langsung atas apa yang anda harapkan pada transisi, anda
dapat menerapakan class CSS pada setiap tahap transisi.

*contoh berikut menggunakan utility class dari TailwindCSS


58
<div x-data="{ open: false }">
<button @click="open = ! open">Toggle</button>

<div
x-show="open"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-90"
>Hello 👋</div>
</div>

Directive Description

:enter diterapkan selama memasuki fase entering

:enter- ditambahkan sebelum element dimasuki, hapus satu frame


start setelah element dimasuki

Menambahkan satu frame setelah element dimasuki (pada


:enter-
saat yang sama enter-start dihapus), dihapus ketika
end
transisi/animasi selesai.

:leave diterapkan selama fase leaving seluruhnya

:leave- Ditambahkan segera ketika sebuah transisi leaving terpicu,


start dihapus setelah 1 frame.

menambahkan 1 frame setelah transisi leaving (pada saat


:leave-
yang sama leave-start dihapus), dihapus ketika transisi
end
/animasi selesai

x-effect
x-effect berguna untuk evaluasi ulang sebuah ekspresi ketika salah satu
dependensi berubah. Anda dapat berpikir ini adalah sebuah pengawas
(watcher) dimana anda tidak harus menentukan properti apa
yang perhatikan, direktif ini akan memperhatikan semua properti yang
digunakan dengannya.

59
Jika definisi ini membingungkan anda, tidak apa-apa. Lebih baik
dijelaskan melalui sebuah contoh:
<div x-data="{ label: 'Hello' }" x-effect="console.log(label)">
<button @click="label += ' World!'">Change Message</button>
</div>

ketika komponen ini dimuat, ekspresi x-effect akan berjalan dan “Hello
“akan di log ke console.

Karena Alpine tahu tentang referensi properti manapun berisi x-effect,


ketika tombol diklik dan label berubah, efek akan memicu ulang dan “Hello
World” akan di log ke console.

x-ignore
secara bawaan, Alpine mengikis atau menelusuri dan menginisialisasi
seluruh DOM tree dari sebuah elemen yang terdapat x-init atau x-data

Jika untuk beberapa alasan, anda tidak ingin bersentuhan dengan spesifik
bagian dari HTML anda, anda dapat mencegahnya dengan melakukan x-
ignore.

<div x-data="{ label: 'From Alpine' }">


<div x-ignore>
<span x-text="label"></span>
</div>
</div>;

Pada contoh diatas tag <span> akan berisi “From Alpine” karena kita
memberitahu Alpine untuk mengabaikan konten dari div seluruhnya.

x-ref
x-ref dalam kombinasi dengan $refs merupakan sebuah utility yang
berguna untuk mengakses elemen DOM engan mudah secara
langsung. Ini sangat berguna sebagai sebuah pengganti elemen API
seperti getElementById dan querySelector.

<button @click="$refs.text.remove()">Remove Text</button>

<span x-ref="text">Hello 👋</span>

60
x-cloak
Terkadang, ketika anda menggunakan AlpineJS untuk bagian dari
template anda, ada sebuah “blip” (kesalahan) ketika anda mungkin
melihat tempate tidak terinisialisasi setelah halaman dimuat, tapi
sebelum Alpine dimuat.

x-cloak membahas skenario ini dengan menyembunyikan elemen dan


disisipkan sampai Alpine di muat sepenuhnya pada halaman.

Agar x-cloak berfungsi, Anda harus menambahkan CSS berikut ke


halaman

[x-cloak] { display: none !important; }


Sekarang, contoh berikut akan menyembunyikan tag <span> sampai Alpine
set text content ke property message.

<span x-cloak x-text="message"></span>;

ketika Alpine memuat halaman, Alpine menghapus semua properti x-


cloak dari elemen, yang juga menghapus display: none; yang diterapkan
oleh CSS, karenanya elemen ditampilkan.

Jika anda ada ingin mencapai perilaku yang sama seperti ini, tapi
menghindari memasukkan global style, anda dapat menggunakan
trik keren berikut, tapi memang triknya aneh:

<template x-if="true">
<span x-text="message"></span>
</template>;

Ini akan menghasilkan gol yang sama seperti x-cloak hanya dengan
memanfaatkan cara kerja x-if

Karena elemen <template> “disembunyikan” di peramban secara


default, Anda tidak akan melihat <span> sampai Alpine memiliki
kesempatan untuk merender x-if="true" dan menampilkannya.

Lagi, solusi ini bukan untuk semua orang, tapi pantas untuk disebut untuk
kasus yang khusus.

61
x-teleport
directive x-teleport memungkinkan anda untuk mengangkut bagian dari
template Alpin Anda ke bagian DOM lain pada halaman sepenuhnya.

Direktif ini berguna untuk sesuatu seperti modal (khususnya yang yang
bersarang), dimana ini berguna untuk keluar dari set z-index dari
komponen Alpine saat ini.

**peringatan: jika anda adalah pengguna Livewire, fungsi ini tidak akan
bekerja di dalam komponen Livewire. Dukungan untuk ini masih di dalam
road map.

x-teleport

Dengan melampirkan x-teleport ke sebuah elemen <template>, anda


memberitahu Alpine untuk menambahkan elemen ke selector yang
tersedia.

* <template> selector dapat menjadi string apapun yang normalnya dioper


ke dalam sesuatu seperti document.querySelector. Ini akan menemukan
elemen pertama yang cocok, mungkin nama tag (body), nama class (.my-
class ), ID (#my-id )atau CSS selector valid yang lain.

Berikut ini adalah contoh modal yang dibuat.

<body>
<div x-data="{ open: false }">
<button @click="open = ! open">Toggle Modal</button>

<template x-teleport="body">
<div x-show="open">
Modal contents...
</div>
</template>
</div>

<div>Some other content placed AFTER the modal markup.</div>

...

</body>

62
perhatikan bagaimana ketika toggling modal, actual content model
ditampilkan SETELAH “Some other content...”? Ini karena ketika Alpine
menginisialisasi, Alpine melihat x-teleport="body" dan menambahkan dan
menginisialisasi elemen ke selector elemen yang disediakan.

Forwarding event

Mencoba yang terbaik untuk membuat pengalaman dari teleporting tidak


berasa. Apapun yang yang normalnya anda lakukan di sebuah
template, anda ada seharusnya dapat melakukannya di dalam sebuah
template x-teleport. Konten yang telah ditelepon dapat diakses pada
scope sebagai komponen normal Alpine juga fitur lain seperti $refs, $root
dan lain-lain.

Meskipun, DOM event asli tidak memiliki konsep teleportasi, sebagai


contoh, Anda memicu sebuah event “click” dari dalam elemen yang telah
teleport, event tersebut akan menggembung ke atas ke DOM tree seperti
normalnya.

Untuk membuat pengalaman ini lebih mulus, Anda dapat “forward” event
dengan mendaftarkan event listener pada elemen <template x-teleport...>
seperti:

<div x-data="{ open: false }">


<button @click="open = ! open">Toggle Modal</button>

<template x-teleport="body" @click="open = false">


<div x-show="open">
Modal contents...
(click to close)
</div>
</template>
</div>

Perhatikan bahwa kita kini bisa mendengarkan event dispatch dari elemen
teleport dari luar elemen <template> itu sendiri?

Alpine melakukan ini dengan mendaftarkan event listener pada <template


x-teleport...> dan menghentikan event dari propagating past
live, teleported, DOM element. Kemudian membuat sebuah copy dari
event dan dispatches ulang dari <template x-teleport...>.

63
Nesting

Teloportasi khususnya berguna jika anda mencoba membuat modal


bersarang satu dengan yang lainnya Alpine membuat ini menjadi
sederhana dengan melakukan:

<div x-data="{ open: false }">


<button @click="open = ! open">Toggle Modal</button>

<template x-teleport="body">
<div x-show="open">
Modal contents...

<div x-data="{ open: false }">


<button @click="open = ! open">Toggle Nested Modal</button>

<template x-teleport="body">
<div x-show="open">
Nested modal contents...
</div>
</template>
</div>
</div>
</template>
</div>

setelah toggling kedua modal “on”, modal sebagai children, tapi akan di
render sebagai sibling elemen pada halaman, tidak dalam satu sama
lainnya.

x-if

x-if digunakan untuk beralih (toggling) elemen di halaman, mirip


dengan x-show, meskipun x-show sepenuhnya menambah dan menghapus
elemen yang diterapkan tidak hanya mengubah CSS properti ke
display “none”.

Karena ini merupakan perilaku yang berbeda, x-if tidak harus diterapkan
secara langsung ke element, tapi tag <template> yang membungkus
element. Cara ini, ini Alpine dapat menjaga catatan dari elemen sekali
saat dihapus dari halaman.

<template x-if="open">
<div>Contents...</div>

64
</template>;

* tidak seperti x-show, x-if, TIDAK mendukung transisi peralihan dengan x-


transition

*ingat: tag <template> hanya dapat berisi 1 root-level elemen.

x-id
x-id memungkinkan anda untuk mendeklarasikan “scope” baru untuk ID
baru manapun yang dihasilkan menggunakan $id(). x-id menerima
sebuah array string (ID name) dan menambahkan sebuah akhiran ke
setiap $id('...') yang dihasilkan yang unik daripada ID lain di halaman.

x-id dimaksudkan untuk digunakan dalam konsumsi dengan magic


$id(...)

Ini adalah contoh dari direktif ini:

<div x-id="['text-input']">
<label :for="$id('text-input')">Username</label>
<!-- for="text-input-1" -->

<input type="text" :id="$id('text-input')">


<!-- id="text-input-1" -->
</div>

<div x-id="['text-input']">
<label :for="$id('text-input')">Username</label>
<!-- for="text-input-2" -->

<input type="text" :id="$id('text-input')">


<!-- id="text-input-2" -->
</div>

65
Magics
$el
$el merupakan sebuah properti magic yang dapat digunakan
untuk mengambil node DOM saat ini.

<button @click="$el.innerHTML = 'Hello World!'">Replace me with "Hello


World!"</button>

$refs
$refs merupakan sebuah properti magic yang dapat digunakan untuk
mengambil DOM elemen yang ditandai dengan x-ref di dalam komponen.
Ini berguna ketika anda memerlukan manipulasi DOM element secara
manual ini sering digunakan sebagai sebuah alternatif yang lebih pendek,
dari document.querySelector.

<button @click="$refs.text.remove()">Remove Text</button>

<span x-ref="text">Hello 👋</span>


Sekarang, ketika tombol <button> ditekan, <span> akan dihapus.

$store
anda dapat menggunakan $store dengan nyaman untuk mengakses
global Alpine store yang telah terdaftar menggunakan Alpine.store(…)
Sebagai contoh:

<button x-data @click="$store.darkMode.toggle()">Toggle Dark Mode</button>

...

<div x-data :class="$store.darkMode.on && 'bg-black'">


...
</div>

<script>
document.addEventListener('alpine:init', () => {
Alpine.store('darkMode', {
on: false,

toggle() {
this.on = ! this.on
}
})

66
})
</script>

mengingat bahwa kita telah mendaftarkan store darkMode dan mengatur on


ke “false”, ketika <button> ditekan, on akan menjadi “true” dan warna
background dari halaman akan berubah menjadi hitam.

Single-value Stores

jika anda ada tidak foto seluruh objek untuk sebuah store, anda dapat
mengatur dan menggunakan segala jenis data sebagai sebuah store.

Ini adalah contoh dari atas tapi menggunakan hal yang lebih sederhana
seperti sebuah nilai Boolean:

<button x-data @click="$store.darkMode = ! $store.darkMode">Toggle Dark


Mode</button>

...

<div x-data :class="$store.darkMode && 'bg-black'">


...
</div>

<script>
document.addEventListener('alpine:init', () => {
Alpine.store('darkMode', false)
})
</script>

$watch
Anda dapat “mengawasi” sebuah properti komponen menggunakan
magic method $watch . Sebagai contoh:

<div x-data="{ open: false }" x-init="$watch('open', value =>


console.log(value))">
<button @click="open = ! open">Toggle Open</button>
</div>

Pada contoh diatas, ketika tombol ditekan dan open berubah, callback
yang disediakan akan dipicu dan menambahkan nilai baru ke console.log.

67
Anda dapat mengawasi properti bersarang menggunakan notasi “dot”

<div x-data="{ foo: { bar: 'baz' }}" x-init="$watch('foo.bar', value =>


console.log(value))">
<button @click="foo.bar = 'bob'">Toggle Open</button>
</div>

ketika <button> ditekan, foo.bar akan set ke “bob”, dan “bob” akan di log ke
console.

Getting the “old” value

$watch tetap mengawasi nilai properti sebelumnya, anda dapat


mengaksesnya menggunakan argumen kedua yang bersifat opsional
untuk memanggil callback seperti:

<div x-data="{ open: false }" x-init="$watch('open', (value, oldValue) =>


console.log(value, oldValue))">
<button @click="open = ! open">Toggle Open</button>
</div>
Deep Watching

$watch akan secara otomatis mengawasi perubahan pada level manapun


tapi anda tetap harus ingat bahwa ketika sebuah perubahan
terdeteksi, watcher akan mengembalikan nilai dari properti yang yang di
amati, bukan nilai dari properti yang telah berubah.

<div x-data="{ foo: { bar: 'baz' }}" x-init="$watch('foo', (value, oldValue)


=> console.log(value, oldValue))">
<button @click="foo.bar = 'bob'">Update</button>
</div>

ketika <button> ditekan, foo.bar akan set “bob”, dan "{bar: 'bob'} {bar: 'baz'}"
akan di log ke konsol(baru dan lama)

**mengubah sebuah properti dari objek “watched” sebagai sebuah side


efek dari callback $watch akan menghasilkan sebuah infinite loop dan
dan terkadang error.

<!-- 🚫 Infinite loop -->


<div x-data="{ foo: { bar: 'baz', bob: 'lob' }}" x-init="$watch('foo', value
=> foo.bob = foo.bar)">
<button @click="foo.bar = 'bob'">Update</button>
</div>

68
$dispatch
$dispatch merupakan sebuah jalan pintas yang berguna untuk dispatching
browser event.

<div @notify="alert('Hello World!')">


<button @click="$dispatch('notify')">
Notify
</button>
</div>
Anda dapat juga mengoper data dengan dispatched event jika anda
ingin. Data ini akan bisa diakses sebagai properti .detail dari event:

<div @notify="alert($event.detail.message)">
<button @click="$dispatch('notify', { message: 'Hello World!' })">
Notify
</button>
</div>

di belakang layar, $dispatch merupakan sebuah pembungkus untuk API


yang lebih bertele-tele:
element.dispatchEvent(new CustomEvent(...))

Note on event propagation

Perhatikan, karena event bubbling, ketika anda butuh untuk menangkap


event yang telah di dispatch dari nodes yang dibawa hierarki bersarang
yang sama, anda butuh menggunakan modifier .window:

Contoh:

<!-- 🚫 Won't work -->


<div x-data>
<span @notify="..."></span>
<button @click="$dispatch('notify')">Notify</button>
</div>

<!-- ✅ Will work (because of .window) -->


<div x-data>
<span @notify.window="..."></span>
<button @click="$dispatch('notify')">Notify</button>
</div>

*contoh pertama tidak akan berfungsi karena ketika custom-event di


dispatch, dia akan propagate ke pendahulunya yang umum, div, tidak ke
69
sibling, <span>. Contoh kedua berfungsi karena sibling mendengarkan
notify pada level window, yang di custom event yang pada akhirnya akan
mengelembung.

Dispatching to another Element

Anda dapat mengambil keuntungan dari teknis sebelumnya untuk


membuat komponen anda berbicara satu dengan yang lainnya:

Contoh:

<div
x-data="{ title: 'Hello' }"
@set-title.window="title = $event.detail"
>
<h1 x-text="title"></h1>
</div>

<div x-data>
<button @click="$dispatch('set-title', 'Hello World!')">Click me</button>
</div>
<!-- When clicked, the content of the h1 will set to "Hello World!". -->

Dispatching to x-model

anda dapat menggunakan $dispatch() untuk memicu data update untuk


data x-model binding. Sebagai contoh:

<div x-data="{ title: 'Hello' }">


<span x-model="title">
<button @click="$dispatch('input', 'Hello World!')">Click me</button>
<!-- After the button is pressed, `x-model` will catch the bubbling
"input" event, and update title. -->
</span>
</div>

ini membuka pintu untuk membuat komponen input custom yang


memiliki nilai yang dapat diatur melalui x-model.

$nextTick
$nextTick merupakan sebuah properti magic yang memungkinkan anda
untuk hanya mengeksekusi sebuah ekspresi SETELAH Alpine menerima
reaktif update DOM. Ini berguna setiap kali anda ingin berinteraksi dengan
DOM state SETELAH mencerminkan data apa pun yang anda buat.
70
<div x-data="{ title: 'Hello' }">
<button
@click="
title = 'Hello World!';
$nextTick(() => { console.log($el.innerText) });
"
x-text="title"
></button>
</div>

pada contoh diatas, daripada log “Hello” ke consol, “Hello World!” akan di
log karena $nextTick akan menunggu sampai Alpine selesai melakukan
update DOM.

Promises

$nextTick mengembalikan sebuah promise, mengizinkan penggunaan


$nextTick untuk menghentikan sementara sebuah fungsi yang asinkronus
sampai setelah update DOM yang terpenting selesai. Ketika
menggunakan seperti ini, $nextTick juga tidak memerlukan sebuah
argumen untuk dioper.

<div x-data="{ title: 'Hello' }">


<button
@click="
title = 'Hello World!';
await $nextTick();
console.log($el.innerText);
"
x-text="title"
></button>
</div>

$root
$root merupakan sebuah properti magic yang dapat digunakan untuk
mengambil root elemen dari komponen Alpine manapun. Dengan kata
lain elemen terdekat dari DOM tree yang berisi x-data.

<div x-data data-message="Hello World!">


<button @click="alert($root.dataset.message)">Say Hi</button>
</div>

71
$data
$data merupakan sebuah properti magic yang memberi Anda akses ke
lingkup data Alpine (saat ini umumnya disediakan oleh x-data).

Seringkali Anda dapat hanya mengakses data Alpine dengan ekspresi


secara langsung. Sebagai contoh

x-data="{ message: 'Hello Caleb!' }"


memungkinkan anda melakukan hal seperti x-text="message".

Meskipun, terkadang ini berguna untuk memiliki sebuah objek aktual yang
terenkapsulasi semua scope yang dapat anda oper disekitar fungsi yang
lain.

<div x-data="{ greeting: 'Hello' }">


<div x-data="{ name: 'Caleb' }">
<button @click="sayHello($data)">Say Hello</button>
</div>
</div>

<script>
function sayHello({ greeting, name }) {
alert(greeting + ' ' + name + '!')
}
</script>

Sekarang ketika tombol ditekan, peramban akan memberikan peringatan


Hello Caleb! karena data akan di oper melalui data objek yang berisi
semua lingkup ekspresi Alpine yang dinamakan (@click="...")

kebanyakan aplikasi tidak membutuhkan properti magic ini, tapi ini dapat
sangat berguna untuk utilitas Alpine yang lebih kompleks dan lebih dalam.

$id
$id merupakan sebuah properti magic yang dapat digunakan untuk
menghasilkan ID elemen dan memastikan ID tidak akan bentrok dengan ID
lain dengan nama yang sama pada halaman yang sama.

Utility ini sangat berguna ketika membangun komponen re-


useble (barangkali dalam sebuah template backend) yang
mungkin terjadi beberapa kali di halaman dan menggunakan ID atribut.

72
Sesuatu seperti komponen input, modal, listboxes, dan lain-lain. akan
mendapat manfaat dari utility ini.

Basic Usage

Andai anda memiliki dua input element dihalaman dan anda ingin input
tersebut memiliki sebuah ID unik satu dengan yang lainnya Anda dapat
melakukan hal berikut:

<input type="text" :id="$id('text-input')">


<!-- id="text-input-1" -->

<input type="text" :id="$id('text-input')">


<!-- id="text-input-2" --></input>

seperti yang dapat anda lihat, $id mengambil sebuah string dan
memecahnya dan penambahan akhiran yang unik pada halaman.

Grouping with x-id


Sekarang katakanlah anda ingin memiliki 2 input elemen yang sama, tapi
kali ini anda ingin elemen label untuk masing-masing.

Hal ini menyebabkan masalah, anda kini butuh untuk bisa mereferensi ke
ID yang sama dua kali. Satu untuk atribut for nya <label>, satu lagi untuk
id pada input.

Ini adalah cara yang mungkin Anda pikir dapat menyelesaikan masalah
ini dan sepenuhnya valid:

<div x-data="{ id: $id('text-input') }">


<label :for="id"> <!-- "text-input-1" -->
<input type="text" :id="id"> <!-- "text-input-1" -->
</div>

<div x-data="{ id: $id('text-input') }">


<label :for="id"> <!-- "text-input-2" -->
<input type="text" :id="id"> <!-- "text-input-2" -->
</div>

Pendekatan ini baik-baik saja, tetapi, memiliki name dan store di ID lingkup
komponen serasa rumit.

73
Untuk menyelesaikan tugas yang sama dengan cara yang lebih
fleksibel, anda dapat menggunakan directive x-id untuk dideklarasikan
sebuah “scope id” untuk serangkaian id:

<div x-id="['text-input']">
<label :for="$id('text-input')"> <!-- "text-input-1" -->
<input type="text" :id="$id('text-input')"> <!-- "text-input-1" -->
</div>

<div x-id="['text-input']">
<label :for="$id('text-input')"> <!-- "text-input-2" -->
<input type="text" :id="$id('text-input')"> <!-- "text-input-2" -->
</div>

Seperti yang dapat Anda lihat, x-id menerima sebuah array dari nama
ID. Sekarang penggunaan $id() dalam scope tersebut akan
menggunakan ID yang sama. Pikirkan mereka sebagai “grup id”.

Nesting

anda mungkin telah berintuisi, anda dapat bebas melakukan x-id


bersarang:

<div x-id="['text-input']">
<label :for="$id('text-input')"> <!-- "text-input-1" -->
<input type="text" :id="$id('text-input')"> <!-- "text-input-1" -->

<div x-id="['text-input']">
<label :for="$id('text-input')"> <!-- "text-input-2" -->
<input type="text" :id="$id('text-input')"> <!-- "text-input-2" -->
</div>
</div>

Keyed IDs (For Looping)

Terkadang, berguna untuk menentukan tambahan akhiran pada sebuah


ID untuk tujuan identifikasi dengan sebuah perulangan.

Untuk itu, $id() menerima sebuah parameter kedua opsional yang akan
menambahkan sebuah akhiran dari ID yang dihasilkan.

Contoh yang umum dari kebutuhan ini ialah terkadang seperti komponen
list box yang menggunakan atribut aria-activedescendant
untuk memberitahu teknologi bantu elemen mana yang “aktif” di list:
74
<ul
x-id="['list-item']"
:aria-activedescendant="$id('list-item', activeItem.id)"
>
<template x-for="item in items" :key="item.id">
<li :id="$id('list-item', item.id)">...</li>
</template>
</ul>

ini merupakan contoh dari sebuah listbox yang belum lengkap, tapi tetap
berguna untuk mendemonstrasikan sebuah skenario di mana anda
mungkin membutuhkan setiap ID di dalam sebuah grup untuk tetap unik
di tiap halaman, tapi juga ke dengan sebuah Loop yang dapat anda
referensi sebagai identifikasi dual dalam grup tersebut.

75
Globals
Alpine.data
Alpine.data(...) menyediakan sebuah cara untuk menggunakan ulang
konteks x-data dalam aplikasi anda.

Ini adalah sebuah komponen dropdown yang dibuat sebagai contoh:

<div x-data="dropdown">
<button @click="toggle">...</button>

<div x-show="open">...</div>
</div>

<script>
document.addEventListener('alpine:init', () => {
Alpine.data('dropdown', () => ({
open: false,

toggle() {
this.open = ! this.open
}
}))
})
</script>

Seperti yang dapat Anda lihat kita telah mengekstrak properti dan method
kita biasanya mendefinisikan secara langsung didalam x-data kedalam
sebuah objek komponen Alpine yang terpisah.

Registering from a bundle

Jika anda memilih untuk menggunakan sebuah langkah build


(membangun) untuk kode Alpine anda, anda sebaiknya mendaftarkan
komponen Anda dengan cara berikut:

import Alpine from `alpinejs`


import dropdown from './dropdown.js'

Alpine.data('dropdown', dropdown)

Alpine.start()

76
Ini menggunakan asumsi bahwa anda telah memiliki sebuah file yang
bernama dropdown.js dengan konten berikut:

export default () => ({


open: false,

toggle() {
this.open = !this.open;
},
});

Initial parameter

Sebagai tambahan untuk referensi provider Alpine.data oleh nama mereka


(seperti x-data="dropdown"), anda juga dapat mereferensi mereka sebagai
sebuah fungsi (x-data="dropdown()"). Dengan memanggil mereka sebagai
fungsi secara langsung, Anda dapat mengoper parameter tambahan
untuk digunakan ketika pembuatan inisiasi data objek juga:

<div x-data="dropdown(true)">
Alpine.data('dropdown', (initialOpenState = false) => ({
open: initialOpenState
}))
Sekarang, anda dapat menggunakan ulang objek dropdown, tapi
menyediakannya dengan parameter yang yang berbeda ada Seperti
yang anda butuhkan.

Init functions

jika komponen anda berisi sebuah method init(), Alpine akan secara
otomatis mengeksekusinya sebelum fungsi itu merender
komponen. Sebagai contoh:

Alpine.data("dropdown", () => ({
init() {
// This code will be executed before Alpine
// initializes the rest of the component.
},
}));

77
Using Magic Properties

Jika anda ingin akses method magic atau properti dari sebuah objek
komponen, anda dapat melakukannya menggunakan context this:

Alpine.data('dropdown', () => ({
open: false,

init() {
this.$watch('open', () => {...})
}
}))

Encapsualting directives with x-bind

Jika Anda berharap untuk menggunakan ulang lebih dari pada hanya
data objek dari sebuah komponen, Anda dapat mengeksplorasi seluruh
template Alpine direktif menggunakan x-bind.

Berikut adalah sebuah contoh dari ekstraksi templating detail dari


dropdown komponen kita sebelumnya menggunakan x-bind:

<div x-data="dropdown">
<button x-bind="trigger"></button>

<div x-bind="dialogue"></div>
</div>;

Alpine.data("dropdown", () => ({
open: false,

trigger: {
["@click"]() {
this.open = !this.open;
},
},

dialogue: {
["x-show"]() {
return this.open;
},
},
}));

78
Alpine.store
Alpine menawarkan global state management melalui API Alpine.store().

Registering A Store

Anda dapat mendefinisikan sebuah Alpine store di dalam listener


alpine:init Alpine (jika memasukan Alpine melalui tag <script>) ATAU anda
dapat mendefinisikan sebelumnya memanggil Alpine.start() (jika
mengimpor Alpine ke dalam build ):

Dari script Tag:

<script>
document.addEventListener('alpine:init', () =>{" "}
{Alpine.store("darkMode", {
on: false,

toggle() {
this.on = !this.on;
},
})}
)
</script>;

Dari bundle:

import Alpine from "alpinejs";

Alpine.store("darkMode", {
on: false,

toggle() {
this.on = !this.on;
},
});

Alpine.start();

Accessing store

Anda dapat mengakses data dari Store manapun di dalam ekspresi Alpine
menggunakan magic properti $store:

79
<div x-data:class="$store.darkMode.on && 'bg-black'">...</div>;

Anda dapat juga memodifikasi properti di dalam struktur dan semua yang
bergantung pada properti tersebut akan secara otomatis bereaksi.
Sebagai contoh:

<button x-data @click="$store.darkMode.toggle()">Toggle Dark Mode</button>

Selain itu, anda dapat mengakses sebuah atore secara eksternal


menggunakan Alpine.store() dengan menghilangkan parameter ke-2
seperti:

<script>Alpine.store('darkMode').toggle()</script>;

Initializing stores

Jika anda menyediakan method init() di dalam sebuah store


Alpine, methode ini akan dieksekusi langsung setelah store
didaftarkan. Methode ini berguna untuk menginisialisasi manapun di
dalam store dengan nilai awal yang yang masuk akal.

<script>
document.addEventListener('alpine:init', () =>{" "}
{Alpine.store("darkMode", {
init() {
this.on = window.matchMedia("(prefers-color-scheme: dark)").matches;
},

on: false,

toggle() {
this.on = !this.on;
},
})}
)
</script>;

Perhatikan method baru nit() yang ditambahkan dalam contoh kode


diatas. Dengan tambahan ini, variabel store on akan diset ke preferensi

80
warna milik browser (peramban) sebelum Alpine merender apapun di
halaman.

Single-value Store

anda tidak butuh keseluruhan objek untuk sebuah Store, Anda dapat
mengatur dan menggunakan data jenis apapun sebagai Store.

Ini adalah sebuah contoh dari di atas tapi menggunakan ini yang lebih
sederhana seperti nilai boolean:

<button x-data @click="$store.darkMode = ! $store.darkMode">Toggle Dark


Mode</button>

...

<div x-data :class="$store.darkMode && 'bg-black'">


...
</div>

<script>
document.addEventListener('alpine:init', () => {
Alpine.store('darkMode', false)
})
</script>

Alpine.bind
Alpine.bind(...) menyediakan cara untuk menggunakan ulang objek x-
bind di dalam aplikasi anda.

Ini adalah contoh sederhana. Daripada mengikat atribut secara manual


dengan Alpine:

<button type="button" @click="doSomething()"


:disabled="shouldDisable"></button>

Anda dapat menggabungkan atribut ini kedalam sebuah objek yang


dapat digunakan kembali dan menggunakan x-bind untuk mengikatnya:

<button x-bind="SomeButton"></button>

<script>
document.addEventListener('alpine:init', () => {

81
Alpine.bind('SomeButton', () => ({
type: 'button',

'@click'() {
this.doSomething()
},

':disabled'() {
return this.shouldDisable
},
}))
})
</script>

82
Plugin
Mask Plugin
Mask pluginnya Alpine memungkinkan anda untuk memformat secara
otomatis sebuah kolom input text saat user mengetik.

Ini berguna pada tipe input yang berbeda: nomor telepon, kartu
kredit, jumlah dolar, nomor akun, tanggal l, dan lain-lain.

Installation

anda dapat menggunakan plugin ini dengan cara menginstalnya via NPM
atau menyatakannya dengan tag <script>

Via CDN

Anda dapat menyertakan CDN build dari plugin sebagai tag


<script>, pastikan menyertakannya SEBELUM file inti Alpine JS.

<!-- Alpine Plugins -->


<script defer
src="https://unpkg.com/@alpinejs/mask@3.x.x/dist/cdn.min.js"></script>

<!-- Alpine Core -->


<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>

Via NPM

Anda dapat menginstal Mask dari NPM untuk digunakan dalam bundel
(bundle):

npm install @alpinejs/mask


kemudian inisialisasi Mask dari bundel anda:

mport Alpine from 'alpinejs'


import mask from '@alpinejs/mask'

Alpine.plugin(mask)

...

x-mask

API utama untuk menggunakan plugin ini ialah direktif x-mask.

83
Ayo mulai dengan melihat contoh sederhana dari sebuah input data
tanggal:

<input x-mask="99/99/9999" placeholder="MM/DD/YYYY"></input>


Perhatikan teks yang anda ketik ke dalam kolom input harus mengikuti
format yang disediakan oleh x-mask. Sebagai tambahan dan untuk
memaksa karakter numeric, / juga secara otomatis ditambahkan jika
pengguna tidak mengetiknya pertama kali.

Karakter bebas berikut didukung dalam mask:

Wild card Deskripsi

* karakter apapun

a Hanya karakter alfabet (a-z, A-Z)

9 hanya karakter number(0-9)

Dynamic Masks

Terkadang mask sederhana (contoh (999) 999-9999) tidak cukup


memadai. Pada kasus tersebut x-mask:dynamic mengizinkan anda untuk
men-generate secara dinamis berdasarkan input pengguna.

Ini adalah sebuah contoh dari input kartu kredit yang butuh untuk dirubah
berdasarkan mask jika nomor dimulai dengan nomor “34” atau “37” (yang
berarti ini adalah sebuah kartu American Express dan memiliki format
yang berbeda).

<input x-mask:dynamic="
$input.startsWith('34') || $input.startsWith('37')
? '9999 999999 99999' : '9999 9999 9999 9999'
"></input>

seperti yang dapat Anda lihat di contoh diatas. Setiap kali pengguna
mengetik di dalam kolom input, nilai tersebut akan di oper ke ekspresi
sebagai $input. Berdasarkan $input, mask yang berbeda dimanfaatkan di
dalam kolom.

84
Coba sendiri dengan mengetikkan sebuah nomor yang di mulai dengan
“34” dan yang satu tidak.

x-mask:dynamic juga menerima sebuah fungsi sebagai hasil dari ekspresi


dan akan secara otomatis mengopernya ke input sebagai parameter
pertama sebagai contoh:

<input x-mask:dynamic="creditCardMask">

<script>
function creditCardMask(input) {
return input.startsWith('34') || input.startsWith('37')
? '9999 999999 99999'
: '9999 9999 9999 9999'
}
</script>
Money Inputs

Karena menulis ekspresi mask dinamis anda sendiri untuk input uang
sangatlah kompleks, Alpine menawarkan fungsi tersebut yang telah
dibuat sebelumnya dan tersedia dengan $money()

Ini adalah fungsionalitas input mask uang secara penuh:

<input x-mask:dynamic="$money($input)">
jika ingin menukar dengan titik “.” dengan koma “,” atau sebaliknya(seperti
persyaratan pada mata uang tertentu) Anda dapat melakukannya
menggunakan parameter opsional kedua:

<input x-mask:dynamic="$money($input, ',')">

Intersect Plugin
Intersect plugin merupakan pembungkus untuk intersection observer yang
memungkinkan anda untuk bereaksi dengan mudah ketika sebuah
elemen masuk ke viewport.

Ini berguna untuk: lazy loading gambar dan konten lain, memicu
animasi, scroll tanpa batas, logging “view” dari content, dan lain-lain.

Installation

anda dapat menggunakan plugin ini dengan menginstallnya melalui NPM


atau menyertakannya dari tag <script>.

85
Via CDN

Anda dapat memasukkan CDN yang build dari plugin ini sebagai sebuah
tag <script>, pastikan untuk menyertakan SEBELUM file inti dari Alpine CS.

<!-- Alpine Plugins -->


<script defer
src="https://unpkg.com/@alpinejs/intersect@3.x.x/dist/cdn.min.js"></script>

<!-- Alpine Core -->


<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
Via NPM

Anda dapat menginstal intersect dari NPM untuk digunakan dalam bundel
anda:

npm install @alpinejs/intersect


kemudian inisialisasi dari bundel:

import Alpine from 'alpinejs'


import intersect from '@alpinejs/intersect'

Alpine.plugin(intersect)

...

x-intersect
API utama untuk menggunakan plugin ini adalah x-intersect. Anda dapat
menambahkan x-intersect ke elemen manapun di dalam komponen
Alpine, dan ketika komponen tersebut memasuki area pandang (di scroll
ke area pandang), ekspresi yang disediakan akan dieksekusi.

Sebagai contoh, pada potongan kode berikut, shown tetap bernilai false
sampai elemen di scroll ke bawah. Pada titik ini, ekspresi mengeksekusi
dan shown menjadi true:

<div x-data="{ shown: false }" x-intersect="shown = true">


<div x-show="shown" x-transition>
I'm in the viewport!
</div>
</div>;

x-intersection:enter

86
Akhiran :enter merupakan sebuah alias dari x-intersect, dan berfungsi
dengan cara yang sama.

<div x-intersect:enter="shown = true">...</div>;

Anda mungkin memilih untuk menggunakan ini sebagai penjelas ketika


juga menggunakan akhiran :leave

x-intersect:leave

Penambahan :leave menjalankan ekspresi anda ketika elemen


meninggalkan viewport:

<div x-intersect:leave="shown = true">...</div>;

Modifiers

. once

Terkadang ini berguna untuk mengevaluasi sebuah ekspresi hanya


pertama kali saat elemen memasuki viewport dan tidak pada waktu
berikutnya. Sebagai contoh ketika memicu animasi “enter”. Pada kasus ini
anda dapat menambahkan modifier .once ke x-intersect untuk
mencapainya.

<div x-intersect.once="shown = true">...</div>

.half

Evaluasi ekspresi ketika intersection (persimpangan) melebihi 0.5

Berguna untuk elemen ketika penting untuk ditampilkan paling tidak


bagian dari elemen.

<div x-intersect.half="shown = true">...</div> // when `0.5` of the element is


in the viewport

. full

Evaluasi ekspresi sekali ketika persimpangan melebihi 0.99

Berguna untuk elemen ketika penting untuk menampilkan seluruh elemen

87
<div x-intersect.full="shown = true">...</div> // when `0.99` of the element
is in the viewport

.threshold

Memungkinkan anda untuk mengendalikan properti threshold yang


didasari IntersectionObserver:

Nilai ini harus berada di jangkauan “0-100”. Nilai “0” berarti memicu
sebuah “intersection” jika bagian elemen MANA PUN memasuki
viewport(perilaku bawaan). Ketika sebuah nilai “100” berarti jangan picu
intersection sampai seluruh halaman telah enter sebelumnya.

Nilai apapun di antara persentase ke-2 ekstrem itu.

Sebagai contoh jika anda ingin memicu sebuah intersection setelah


separuh elemen memasuki halaman anda dapat menggunakan
.threshold.50

<div x-intersect.threshold.50="shown = true">...</div> // when 50% of the


element is in the viewport

Jika anda ingin memicu hanya 5% dari elemen yang memasuki viewport
anda dapat menggunakan .threshold.05 dan seterusnya dan seterusnya.

.margin

Memungkinkan anda untuk mengendalikan properti rootMargin dari


IntersectionObserver. Ini secara efektif mengubah ukuran dari batas
viewport. Nilai positif mengembangkan batasan dari viewport dan nilai
negatif menyusutkannya. Nilai bekerja seperti CSS margin: 1 nilai untuk
semua sisi, 2 nilai untuk atas bawah, kiri kanan, atau 4 nilai untuk atas,
kanan, bawah, kiri. Anda dapat juga menggunakan nilai px dan %, atau
menggunakan nomor untuk mendapat nilai pixel.

<div x-intersect.margin.200px="loaded = true">...</div> // Load when the


element is within 200px of the viewport

<div x-intersect:leave.margin.10%.25px.25.25px="loaded = false">...</div> //


Unload when the element gets within 10% of the top of the viewport, or within
25px of the other three edges

88
<div x-intersect:leave.margin.10%.25px.25.25px="loaded = false">...</div> //
Unload when the element gets within 10% of the top of the viewport, or within
25px of the other three edges

Persist Plugin
Persist plugin memungkinkan anda untuk mempertahankan state Alpine di
semua halaman.

Ini berguna untuk mempertahankan filter pencari, active tab dan fitur lain
dimana pengguna akan frustasi jika konfigurasi mereka di-reset setelah
merefresh atau meninggalkan dan mengunjungi ulang halaman.

Installation

Anda dapat menggunakan plugin ini dengan memasukkannya melalui


tag <script> atau menginstal melalui NPM.

Via CDN

Anda dapat memasukkan CDN build pada plugin ini sebagai sebuah tag
<script>, pastikan masukkannya SEBELUM file inti Alpine JS.

<!-- Alpine Plugins -->


<script defer
src="https://unpkg.com/@alpinejs/persist@3.x.x/dist/cdn.min.js"></script>

<!-- Alpine Core -->


<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
Via NPM

Anda dapat menginstal Persist dari NPM untuk digunakan dalam bundel
anda:

npm install @alpinejs/persist


kemudian inisialisasi Persist dari bandel anda.

import Alpine from 'alpinejs'


import persist from '@alpinejs/persist'

Alpine.plugin(persist)

...

89
$persist

API utama untuk menggunakan plugin ini adalah method magic $persist

Anda dapat membungkus nilai apapun di dalam x-data dengan $persist


seperti di bawah untuk untuk menahan nilai tersebut di seluruh halaman
ketika dimuat:

<div x-data="{ count: $persist(0) }">


<button x-on:click="count++">Increment</button>

<span x-text="count"></span>
</div>;

Pada contoh diatas, karena kita membungkus 0 dalam $persist(), Alpine


sekarang menahan perubahan yang dibuat count dan
mempertahankannya di seluruh halaman.

Anda dapat mencoba sendiri dengan menambah “count” pada contoh


diatas, lalu muat ulang halaman tersebut dan perhatikan bahwa “count”
menjaga state dan tidak meresetnya ke “0”

How does it works?

Jika sebuah nilai dibungkus dalam $persist, ada inisialisasi Alpine akan
mendaftarkan wwatcher sendiri untuk nilai tersebut. Sekarang setiap kali
nilai berubah untuk alasan apapun Alpine akan menyimpan nilai baru ke
dalam localstorage.

Sekarang ketika sebuah halaman di muat ulang, Alpine akan memeriksa


nilai localstorage (menggunakan nama dari properti sebagai key untuk
nilai). Jika ditemukan, $persist akan mengatur nilai property dari
localStorage secepat mungkin.

Anda dapat mengatasi perilaku ini dengan membuka devtools


localstorage di browser anda:

90
Anda akan mendapat mengamati bahwa dengan mengunjungi halaman
ini, Alpine telah mengatur nilai “count” didalam localstorage. Ada juga
menyadari imbuhan nama property “count” dengan “x” sebagai cara
nama spasi dari nilai ini jadi Alpine tidak bentrok dengan tool lain yang
menggunakan localStorage.

Sekarang ubah “count” sesuai contoh berikut dan amati perubahan yang
Alpine buat ke localstorage.

<div x-data="{ count: $persist(0) }">


<button x-on:click="count++">Increment</button>

<span x-text="count"></span>
</div>;
$persist bekerja dengan nilai primitif seperti array dan objek. Meskipun
perlu diperhatikan bahwa localstorage harus dihapus ketika tipe variabel
berubah. Mengingat contoh sebelumnya, jika kita mengubah nilai dari
$persist({ value: 0 }) , kemudian localstorage akan menghapus atau
memberi nama ulang ke variabel “count”.

Setting a custom key

Secara default, Alpine menggunakan properti key yang $persist(...) yang


ditugaskan (ke “count” dalam contoh diatas).

Perhatikan skenario di mana anda memiliki banyak komponen Alpine


diseluruh halaman atau meski pada halaman yang sama yang yang
semuanya menggunakan “count” sebagai properti key.

Alpine tidak memiliki cara untuk membedakan antar komponen ini.

Pada kasus ini, anda dapat mengatur custom key ke anda sendiri untuk
mempertahankan nilai apapun menggunakan modifier .as:

91
<div x-data="{ count: $persist(0).as('other-count') }">
<button x-on:click="count++">Increment</button>

<span x-text="count"></span>
</div>;

Sekarang Alpine akan menyimpan dan mengambil nilai “count” diatas


menggunakan key “outher-count”.

Ini adalah tampilan Chrome Dev tool untuk Anda lihat sendiri.

Using a custom storage

Secara bawaan, data yang telah disimpan di localStorage. Tidak memiliki


waktu kedaluwarsa dan akan tetap disimpan meski halaman telah
ditutup.

Perhatikan skenario di mana anda ingin menghapus data setiap kali user
menutup tab. Pada kasus ini anda dapat mempertahankan data ke
sessionStorage menggunakan modifier .using:

<div x-data="{ count: $persist(0).using(sessionStorage) }">


<button x-on:click="count++">Increment</button>

<span x-text="count"></span>
</div>;

Anda juga dapat menentukan objek custom storage yang mengekspos


sebuah function getItem dan setItem, anda dapat menentukan untuk
menggunakan session cookie sebagai penyimpanan:

<script>

92
window.cookieStorage = {
getItem(key) {
let cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) {
let cookie = cookies[i].split("=");
if (key == cookie[0].trim()) {
return decodeURIComponent(cookie[1]);
}
}
return null;
},
setItem(key, value) {
document.cookie = key+' = '+encodeURIComponent(value)
}
}
</script>

<div x-data="{ count: $persist(0).using(cookieStorage) }">


<button x-on:click="count++">Increment</button>

<span x-text="count"></span>
</div>;

Using $persist with Alpine.data

jika anda menggunakan $persist dengan Alpine.data, anda perlu sebuah


fungsi standar alih-alih sebuah arrow function jadi Alpine dapat mengikat
sebuah custom context this ketika persis evaluasi lingkup komponen.

Alpine.data("dropdown", function () {
return {
open: this.$persist(false),
};
});

Using $persist with Alpine global

Alpine.$persist dieksposes secara global jadi dapat digunakan diluar


context x-data. Ini berguna untuk mempertahankan data dari sumber lain
seperti Alpine.store

Alpine.store("darkMode", {
on: Alpine.$persist(true).as("darkMode_on"),
});

93
Focus Plugin
*perhatikan: Plugin ini sebelumnya bernama “Trap”. fungsi Trap telah di
serap ke dalam plugin ini dengan tambahan fungsi. Anda dapat
menggeser ke fokus tanpa apa perubahan dan yang rusak.

Focus milik Alpine memungkinkan anda untuk mengatur fokus pada


sebuah halaman.

*Plugin ini secara internal banyak menggunakan alat open source


Tabbable. Terima kasih banyak untuk tim yang menyediakan banyak
solusi pada masalah ini.

Installation

Anda dapat menggunakan plugin baik menyertakannya melalui tag


<script> atau menginstalnya melalui NPM.

Via CDN

Anda dapat memasukkan CDN build pada plugin ini sebagai sebuah tag
<script>, pastikan masukkannya SEBELUM file inti Alpine JS.

<!-- Alpine Plugins -->


<script defer
src="https://unpkg.com/@alpinejs/focus@3.x.x/dist/cdn.min.js"></script>

<!-- Alpine Core -->


<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>

Via NPM

Anda dapat menginstal Focus dari NPM untuk digunakan didalam bundel
anda.

npm install @alpinejs/focus


kemudian inisialisasi dari bundel anda:

import Alpine from 'alpinejs'


import focus from '@alpinejs/focus'

Alpine.plugin(focus)

...

94
x-trap

Focus menawarkan sebuah API untuk menangkap focus didalam sebuah


elemen: direktif x-trap

x-trap menerima sebuah ekspresi JavaScript. Jika hasil dari ekspresi


adalah true, terlalu fokus akan terjebak di dalam elemen sampai ekspresi
menjadi false, pada titik ini, fokus akan dikembalikan dimana fokus berada
sebelumnya.

Sebagai contoh:

<div x-data="{ open: false }">


<button @click="open = true">Open Dialog</button>

<span x-show="open" x-trap="open">


<p>...</p>

<input type="text" placeholder="Some input...">

<input type="text" placeholder="Some other input...">

<button @click="open = false">Close Dialog</button>


</span>
</div>

Nesting dialogs

Terkadang Anda ingin mencari satu dialog di dalam dialog lainnya. x-trap
membuatnya mudah untuk menanganinya secara otomatis.

x-trap menjaga elemen baru yang “terperangkap” dan menyimpan


aktivitas elemen fokus sebelumnya. Setiap elemen “terlepas” focus akan
mengembalikan ke lokasi awal.

Mekanisme ini rekursif, Jadi anda dapat menangkap fokus yang telah
tertangkap di elemen tanpa batas kemudian “melepasnya” setiap elemen
secara secara berurutan.

Ini adalah contohnya:

<div x-data="{ open: false }">


<button @click="open = true">Open Dialog</button>

<span x-show="open" x-trap="open">

95
...

<div x-data="{ open: false }">


<button @click="open = true">Open Nested Dialog</button>

<span x-show="open" x-trap="open">

...

<button @click="open = false">Close Nested Dialog</button>


</span>
</div>

<button @click="open = false">Close Dialog</button>


</span>
</div>

Modifier

.inert

Ketika membangun seperti modal atau dialog, direkomendasikan untuk


menyembunyikan semua elemen lain di halaman dari pembaca layar
ketika focus terperangkap.

Dengan menambahkan .inert ke x-trap, fokus akan terperangkap, semua


elemen lain pada halaman akan menerima atribut aria-hidden="true", dan
focus trapping akan dimatikan, atribut ini juga akan dihapus.

<!-- When `open` is `false`: -->


<body x-data="{ open: false }">
<div x-trap.inert="open" ...>
...
</div>

<div>
...
</div>
</body>

<!-- When `open` is `true`: -->


<body x-data="{ open: true }">
<div x-trap.inert="open" ...>
...
</div>

96
<div aria-hidden="true">
...
</div>
</body>

.noscroll

Ketika membangun modal atau dialog dengan Alpine direkomendasikan


anda mematikan scrolling di sekitar konten ketika dialog terbuka.

x-trap memungkinkan anda untuk melakukan ini secara otomatis dengan


modifier .noscroll.

Dengan menambahkan .noscroll, Alpine akan menghapus scrollbar dari


halaman dan memblok pengguna dari melakukan scroll (gulir) halaman
ke bawah saat dialog dibuka.

Sebagai contoh:

<div x-data="{ open: false }">


<button>Open Dialog</button>

<div x-show="open" x-trap.noscroll="open">


Dialog Contents

<button @click="open = false">Close Dialog</button>


</div>
</div>

.noreturn

Terkadang anda tidak ingin focus dikembalikan ke tempat semula.


Pertimbangkan bahwa sebuah dropdown yang memicu focus input,
mengembalikan focus ke input saat ditutup yang akan memicu dropdown
dibuka lagi.

x-trap memungkinkan Anda mematikan perilaku ini dengan modifier


.noreturn

Dengan menambahkan .noreturn Alpine akan tidak mengembalikan fokus


x-trap evaluasi ke false.

Sebagai contoh:

97
div x-data="{ open: false }" x-trap.noreturn="open">
<input type="search" placeholder="search for something" />

<div x-show="open">
Search results

<button @click="open = false">Close</button>


</div>
</div>

$fokus

Plugin ini menawarkan banyak utility kecil untuk mengatur fokus di dalam
halaman. Utilitas ini diekspos melalui magic $focus

Property Deskripsi

Fokuskan elemen yang dilewati (menangani gangguan


focus(el)
secara internal menggunakan nexttick dan lain-lain).

Deteksi weather atau bukan elemen yang memiliki


focusable(el)
kemampuan fokus

focusables() Dapatkan semua “focusable” element pada elemen saat ini

focused() Dapatkan elemen yang difokus saat ini pada halaman

lastFocused() Dapatkan elemen focus terakhir di halaman

Tentukan elemen untuk cakupan magic $focus (elemen


within(el)
saat ini secara default)

first() Fokuskan pada focusable elemen pertama

last() Fokuskan pada focusable elemen terakhir

next() Fokuskan pada focusable elemen selanjutnya

previous() Fokuskan pada focusable elemen sebelumnya

noscroll() Mencegah scrolling ke elemen yang di fokus

98
ketika mengambil “selanjutnya” atau “sebelumnya”
menggunakan “web round” (kecuali mengembalikan
wrap()
elemen pertama jika terdapat elemen “selanjutnya” pada
elemen terakhir

getFirst() Mengambil elemen pertama yang focusable

getLast() Mengambil elemen terakhir yang focusable

getNext() Mengambil elemen selanjutnya yang focusable

getPrevious() Mengambil elemen sebelumnya yang focusable

Ayo lanjut dengan beberapa contoh dari penggunaan utility ini. Contoh di
bawah memungkinkan pengguna untuk mengendalikan fokus di dalam
kelompok tombol menggunakan arraw key (tombol panah). Anda dapat
mengujinya dengan klik pada tombol kemudian menggunakan tombol
panah untuk memindah fokus di sekitar.

<div
@keydown.right="$focus.next()"
@keydown.left="$focus.previous()"
>
<button>First</button>
<button>Second</button>
<button>Third</button>
</div>

Perhatikan jika tombol terakhir yang difokus, tekan “panah kanan” tidak
akan melakukan apapun. Ayo tambahkan method .wrap() sehingga fokus
membungkus semuanya.

<div
@keydown.right="$focus.wrap().next()"
@keydown.left="$focus.wrap().previous()"
>
<button>First</button>
<button>Second</button>
<button>Third</button>
</div>

99
Sekarang, ayo tambahkan 2 tombol, 1 fokus ke elemen pertama dari
kelompok tombol dan fokus lain ke elemen terakhir:

<button @click="$focus.within($refs.buttons).first()">Focus "First"</button>


<button @click="$focus.within($refs.buttons).last()">Focus "Last"</button>

<div
x-ref="buttons"
@keydown.right="$focus.wrap().next()"
@keydown.left="$focus.wrap().previous()"
>
<button>First</button>
<button>Second</button>
<button>Third</button>
</div

Perhatikan bahwa kita butuh menambahkan method .within() untuk


setiap tombol jadi $focus tahu lingkupnya sendiri ke elemen yang berbeda
(div yang membungkus tombol).

Collapse Plugin
Collapse pada Alpine memungkinkan anda mengembangkan dan
meruntuhkan elemen menggunakan transisi yang mulus.
Karena perilaku dan implementasi ini berbeda dari standar sistem transisi
Alpine, fungsionalitas ini telah dibuat ke dalam plugin yang
terdedikasi/dikhususkan.

Installation

Anda dapat menggunakan plugin ini baik dari tag <script> atau
menginstalnya melalui NPM:

Via CDN

Anda dapat memasukkan CDN build dari plugin ini sebagai tag
<script>, pastikan untuk memasukkannya sebelum file inti Alpine JS.

<!-- Alpine Plugins -->


<script defer
src="https://unpkg.com/@alpinejs/collapse@3.x.x/dist/cdn.min.js"></script>

<!-- Alpine Core -->


<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>

100
Via NPM

Anda dapat install Collapse dari NPM untuk digunakan bundel anda:

npm install @alpinejs/collapse


kemudian inisialisasi dari bundel anda:

import Alpine from 'alpinejs'


import collapse from '@alpinejs/collapse'

Alpine.plugin(collapse)

...

x-collapse

API utama untuk penggunaan plugin ini adalah direktif x-collapse

x-collapse hanya ada pada sebuah elemen yang telah memiliki directive
x-show. Ketika ditambahkan sebuah elemen x-show, x-collapse akan secara
mulus “mengembang” dan “meruntuhkan” elemen ketika visibilitasnya di
toggle melalui animasi properti height.

Sebagai contoh:

<div x-data="{ expanded: false }">


<button @click="expanded = ! expanded">Toggle Content</button>

<p x-show="expanded" x-collapse>


...
</p>
</div>

Modifier

.duration

Anda dapat menyesuaikan durasi dari collapse/expand dengan


menambahkan modifier .duration:

<div x-data="{ expanded: false }">


<button @click="expanded = ! expanded">Toggle Content</button>

101
<p x-show="expanded" x-collapse.duration.1000ms>
...
</p>
</div>

.min

Secara bawaan, state “collapsed” mengatur tinggi dari elemen ke 0px dan
juga mengatur display: none;

Terkadang, ini berguna untuk “memotong” sebuah elemen daripada


menyembunyikannya sepenuhnya. Dengan menggunakan modifier .min
Anda dapat mengatur tinggi minimal dari state “collapsed”nya x-collapse
Sebagai contoh:

<div x-data="{ expanded: false }">


<button @click="expanded = ! expanded">Toggle Content</button>

<p x-show="expanded" x-collapse.min.50px>


...
</p>
</div>

Morph Plugin
Plugin Morph memungkinkan anda untuk “mengubah” elemen pada
halaman menjadi template html yang telah disediakan, sambil
mempertahankan peramban (browser) atau state Alpine apapun di
dalam elemen yang “diubah”.

Ini berguna untuk memperbarui HTML dari sebuah request peladen tanpa
kehilangan state pada halaman Alpine. Utility seperti inti adalah ini dari
Framework s full-stack seperti Laravel Livewire dan Phoenix Live View.

Cara terbaik untuk memahami tujuan ini adalah dengan mengikuti


Interactive visual berikut. Mari kita coba.

102
Installation

anda dapat menggunakan plugin ini baik menyertakannya melalui script


<script> atau menginstalnya melalui NPM.

Via CDN

Anda dapat memmasukkan CDN build plugin ini sebagai sebuah tag
<script>, pastikan memasukkannya sebelum file inti Alpine JS.

<!-- Alpine Plugins -->


<script defer
src="https://unpkg.com/@alpinejs/morph@3.x.x/dist/cdn.min.js"></script>

<!-- Alpine Core -->


<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>

Via NPM

Anda dapat menginstal Morph dari NPM untuk digunakan di bundel anda

npm install @alpinejs/morph


lalu inisialisasi dari bundel anda.

103
import Alpine from 'alpinejs'
import morph from '@alpinejs/morph'

window.Alpine = Alpine
Alpine.plugin(morph)

...

Alpine.morph()

Alpine.morph(el, newHtml) memungkinkan anda secara integratif mengubah


sebuah node DOM berdasarkan pada HTML yang dioper. Alpine.morph(el,
newHtml) menerima parameter berikut:

Dom Element pada halaman

Parameter Deskripsi

el DOM element pada halaman

sebuah string dari HTML untuk digunakan sebagai


newHtml
template yang mengubah elemen

sebuah objek opsional digunakan utamanya untuk


options (optional)
injecting life cycle hooks

Ini adalah contoh dari Alpine.morph() untuk memperbarui sebuah


komponen Alpine dengan html baru:(pada aplikasi nyata, html baru ini
akan datang dari peladen)

<div x-data="{ message: 'Change me, then press the button!' }">
<input type="text" x-model="message">
<span x-text="message"></span>
</div>

<button>Run Morph</button>

<script>
document.querySelector('button').addEventListener('click', () => {
let el = document.querySelector('div')

Alpine.morph(el, `
<div x-data="{ message: 'Change me, then press the button!' }">

104
<h2>See how new elements have been added</h2>

<input type="text" x-model="message">


<span x-text="message"></span>

<h2>but the state of this component hasn't changed?


Magical.</h2>
</div>
`)
})
</script>

Lifecycle Hooks

Plugin “Morph” bekerja dengan membandingkan 2 DOM tree, Live element


dan mengoper nya ke dalam HTML.

Morph menyusuri 2 DOM tree secara simultan dan membandingkan setiap


node dan childrennya. Jika ditemukan perbedaan, Morph akan
“menggabungkan” (perubahan) ke DOM tree saat ini untuk pencocokan
dengan HTML yang di oper ke DOM tree.

Sementara alogaritma defaut sangat mampu. Ada kasus di mana anda


ingin hooks ke dalam life cycle dan dan mengamati atau mengubah
perilaku.

Sebelum kita melompat ke lifecycle hoos yang tersedia, ayo pertama


daftar semua parameter potensial yang mereka terima dan penjelasan
dan masing-masing:

ini adalah selalu aktual, saat ini, dan elemen pada halaman
el
akan “ditambal“ (diubah oleh Morph)

Ini adalah sebuah “template elemen”. Ini merupakan elemen


sementara yang mencerminkan apa yang sedang el akan
toEl
tambal. el tidak secara aktual tampil dihalaman dan hanya
digunakan untuk tujuan referensi.

Fungsi ini dapat dipanggil di dalam hook untuk


childrenOnly() memberitahu Morph untuk melewati elemen saat ini dan
hanya “menambal” (patch) dan elemen childrennya.

105
Sebuah fungsi yang dapat ketika dipanggil dalam “hook”
skip() akan melewati pembandingan atau penambalannya sendiri
dan children dari Element saat ini.

Ini tersedia lifecycle hooks (dioper sebagai parameter ketiga


Alpine.morph(..., options)):

Option Deskripsi

updating(el, toEl, dipanggil sebelum patching el dengan


childrenOnly, skip) perbandingan toEl

updated(el, toEl) dipanggil setelah Morph di patch el

dipanggil sebelum Morph menghapus sebuah


removing(el, skip) elemen dari live DOM

Dipanggil setelah Morph menghapus sebuah


removed(el)
elemen dari live DOM

adding(el, skip) dipanggil sebelum penambahan elemen baru

dipanggil setelah penambahan elemen baru ke


added(el)
live DOM tree

sebuah fungsi re-useable untuk menentukan cara


key(el) “keys” Morph elemen dalam DOM tree sebelum di
bandingkan atau tambal.

sebuah nilai boolean yang memberitahu Morph


untuk mengaktifkan sebuah ekstraksi fitur dalam
algoritma yang “melihat kedepan” untuk
lookahead
memastikan sebuah DOM elemen seharusnya
dihapus alih-alih hanya “dipindahkan” ke sibling
nanti.

106
.

Ini adalah kode dari semua lifecycle untuk referensi yang lebih konkrit:

Alpine.morph(el, newHtml, {
updating(el, toEl, childrenOnly, skip) {
//
},

updated(el, toEl) {
//
},

removing(el, skip) {
//
},

removed(el) {
//
},

adding(el, skip) {
//
},

added(el) {
//
},

key(el) {
// By default Alpine uses the `key=""` HTML attribute.
return el.id;
},

lookahead: true, // Default: false


});

Keys

Utility pembeda-DOM seperti Morph mencoba hal terbaik mereka untuk


secara akurat “mengubah” original DOM ke dalam html baru. Meskipun
ada kasus di mana tidak mungkin untuk menentukan jika sebuah elemen
harus diubah atau dihapus seluruhnya.

107
Karena batasan ini, Morph memiliki sebuah sistem “key” yang
memungkinkan developer untuk memaksa elemen tertentu ditahan
daripada menggantinya.

Penggunaan umum kasus ini Ini adalah sebuah daftar sibling di dalam
sebuah pengulangan. Dibawah ini adalah contoh alasan key terkadang
dibutuhkan.

<!-- "Live" Dom on the page: -->


<ul>
<li>Mark</li>
<li>Tom</li>
<li>Travis</li>
</ul>

<!-- New HTML to "morph to": -->


<ul>
<li>Travis</li>
<li>Mark</li>
<li>Tom</li>
</ul>

Mengingat situasi di atas, Morph tidak memiliki cara untuk tahu bahwa
node “Travis” telah dihapus dari DOM tree. Pikirkan bahwa “Mark” telah
berubah ke “Travis” dan “Travis” berubah ke “Tom”.

Ini bukan yang sebenarnya kita inginkan, kita ingin untuk menyimpan
elemen original alih-alih mengubahnya, MEMINDAHKAN mereka ke dalam
<ul>.

Dengan menambahkan keys di setiap node kita dapat mencapai ini:

<!-- "Live" Dom on the page: -->


<ul>
<li key="1">Mark</li>
<li key="2">Tom</li>
<li key="3">Travis</li>
</ul>

<!-- New HTML to "morph to": -->


<ul>
<li key="3">Travis</li>
<li key="1">Mark</li>
<li key="2">Tom</li>
</ul>

108
Sekarang terdapat “keys” di <li>, Morph mencocokkan mereka ke-2 DOM
tree dan memindah mereka.

Anda dapat melakukan konfigurasi Morph untuk pertimbangkan sebuah


“key” dengan konfigurasi opsional key:.

109
Advanced
Reactivity
Alpine merupakan “reaktif” dalam arti ketika anda mengubah bagian dari
data, semua yang bergantung pada data tersebut secara otomatis
bereaksi pada perubahan tersebut.

Setiap reaktivitas kecil yang yang terjadi di Alpine, terjadi karena 2 fungsi
reaktif penting di inti Alpine: Alpine.reactive() dan Alpine.effect()

*Alpine menggunakan engine reactivity-nya VueJS di belakang layar


untuk menyediakan fungsi ini.

Memahami 2 fungsi yang diatas memberi anda kekuatan super sebagai


developer Alpine tapi juga sebagai seorang web Developer secara umum.

Alpine.reactive()

Mari kita lihat pada Alpine.reactive(). Fungsi ini menerima sebuah object
JavaScript sebagai parameter dan mengembalikan sebuah versi “reaktif”
dari objek tersebut. Sebagai contoh:

let data = { count: 1 };

let reactiveData = Alpine.reactive(data);

Di belakang layar, ketika Alpine.reactive menerima data. Data tersebut


akan dibungkus dalam sebuah proxy custom JavaScript.

Sebuah proxy merupakan objek yang spesial di JavaScript yang dapat


mencegat “get” dan “set” untuk memanggil sebuah object JavaScript.

Pada nilai nominal, reactiveData harusnya berperilaku sama seperti data


Sebagai contoh:

onsole.log(data.count); // 1
console.log(reactiveData.count); // 1

reactiveData.count = 2;

console.log(data.count); // 2
console.log(reactiveData.count); // 2

110
Apa yang Anda lihat disini ini terjadi karena reactiveData ialah pembungkus
kecil disekitar data, setiap upaya untuk get atau set sebuah properti akan
berperilaku tepat seperti ini seperti jika anda berinteraksi dengan data
secara langsung.

Perbedaan utama di sini adalah kapanpun anda memodifikasi dan


mengambil sebuah value dari reactiveData, Alpine menyadarinya dan
akan mengeksekusi logic lain manapun yang bergantung pada data itu.

Alpine.reactive hanya bagian pertama dari cerita. Alpine.effect adalah


bagian yang lain mari kita dalami.

Alpine.effect()

Alpine.effect menerima sebuah fungsi callback tunggal. Begitu


Alpine.effect dipanggil, Dia akan menjalankan fungsi yang
disediakan, tapi secara aktif melihat interaksi manapun dengan data
reaktif. Jika terdeteksi sebuah interaksi (sebuah get atau set dari proxy
reaktif) Alpine.effect akan menjaganya dan memastikan callback
dijalankan ulang jika ada data reaktif apapun yang berubah di masa
depan. Sebagai contoh:

let data = Alpine.reactive({ count: 1 });

Alpine.effect(() => {
console.log(data.count);
});

Ketika kode ini dijalankan, “1” akan di log ke console. Kapanpun data.count
berubah nilai akan di log ke console lagi.

Ini merupakan mekanisme yang membuka kunci semua reactivity pada


inti dari Alpine.

Untuk menyambungkan ke titik selanjutnya. Ayo perhatikan sebuah


component “counter” sederhana tanpa menggunakan syntax Alpine sama
sekali, hanya menggunakan Alpine.reactive dan Alpine.effect

<button>Increment</button>;

111
Count: <span></span>;

let button = document.querySelector("button");


let span = document.querySelector("span");

let data = Alpine.reactive({ count: 1 });

Alpine.effect(() => {
span.textContent = data.count;
});

button.addEventListener("click", () => {
data.count = data.count + 1;
});

Seperti yang dapat Anda lihat, anda dapat membuat data reaktif
apapun. Dan dapat juga dapat membungkus kedalam fungsionalitas
manapun didalam Alpine.effect

Kombinasi ini membuka kunci paradigma programming yang sangat


powerfull untuk web development. Berlari liar dan bebas.

Extending
Alpine memiliki basis code yang dibuka yang memungkinkan ekstensi
dalam beberapa cara. Faktanya, setiap directive dan magic yang
tersedia di Alpine sendiri menggunakan API yang tepat. Dalam teori anda
dapat membangun ulang semua fungsionalitas Alpine dan
menggunakannya untuk anda sendiri.

Lifecycle concerns

Sebelum kita mendalami setiap individual API, pertama mari kita bahas
tentang lokasi basis kode anda harus API.

Karena API memiliki dampak pada cara Alpine menginisialisasi


halaman, mereka harus didaftarkan SETELAH Alpine di download dan
tersedia di halaman, tapi SEBELUM halaman tersebut diinisialisasi.

112
Ada dua teknik berbeda bergantung pada ada jika anda mengimpor
Alpine kedalam bundel atau masukkannya melalui tag <script>. Mari lihat
keduanya:

Via a script tag

Jika anda memasukkan Alpine melalui tag <script>, anda butuh


mendaftarkan extensi custom lainnya di dalam event listener Alpine
alpine:init

Ini contohnya:

<html>
<script src="/js/alpine.js" defer></script>

<div x-data x-foo></div>

<script>
document.addEventListener('alpine:init', () => {
Alpine.directive('foo', ...)
})
</script>
</html>

Jika anda ingin mengekstrak ekstensi kode anda sendiri kedalam sebuah
file eksternal, anda perlu memastikan bahwa file tag <script> tersebut
berlokasi SEBELUM file Alpine.

<html>
<script src="/js/foo.js" defer></script>
<script src="/js/alpine.js" defer></script>

<div x-data x-foo></div>


</html>;

Via an NPM module

jika anda mengimpor Alpine kedalam sebuah bundel, Anda harus


memastikan Anda meregistrasi kode ekstensi apa pun DI ANTARANYA
ketika anda mengimpor objek global Alpine dan ketika anda
menginisialisasi Alpine dengan memanggil Alpine.start() . Sebagai contoh:

import Alpine from 'alpinejs'

113
Alpine.directive('foo', ...)

window.Alpine = Alpine
window.Alpine.start()

Sekarang kita tahu dimana menggunakan API extension ini, mari lihat
lebih dekat bagaimana penggunaan masing-masing:

Custom Directive

Alpine memungkinkan anda untuk mendaftarkan directive custom anda


sendiri menggunakan API Alpine.directive()

Method Signature

Alpine.directive(
"[name]",
(el, { value, modifiers, expression }, { Alpine, effect, cleanup }) => {});

Name nama dari direktif. Nama “foo” untuk contoh akan


name
dikonsumsi sebagai x-foo

el DOM element directive yang ditambahkan ke

ke jika disediakan, bagian direktif setelah titik dua. Contoh 'bar'


value
di dalam x-foo:bar

Array dari tambahan trailing yang dipisah dengan titik ke


modifiers
directive. Contoh ['baz', 'lob'] dari x-foo.baz.lob

expression Bagian nilai atribut dari directive. Contoh: law dari x-foo=”law”

Alpine global objek Alpine

sebuah fungsi untuk membuat efek reaktif yang akan otomatis


effect
membersihkan setelah direktif ini dihapus dari DOM

sebuah fungsi yang dapat mengoperkan callback yang akan


cleanup
terlebih dijalankan ketika directive unu dihapus dari DOM

114
Simple Example

ini merupakan sebuah contoh sederhana directive kita akan membuat


direksi bernama x-uppercase

Alpine.directive('uppercase', el => {
el.textContent = el.textContent.toUpperCase()
})

<div x-data>
<span x-uppercase>Hello World!</span>
</div>

Evaluating expressions

Ketika mendaftarkan sebuah directive custom, anda mungkin ingin untuk


mengevaluasi expresi JavaScript yang di sediakan oleh pengguna:

sebagai contoh, Katakanlah anda ingin membuat sebuah custom


directive sebagai sebuah shortcut untuk console.log().

Seperti berikut:

<div x-data="{ message: 'Hello World!' }">


<div x-log="message"></div>
</div>;
Anda butuh untuk mengambil nilai asli dari message dengan
mengevaluasinya sebagai ekspresi JavaScript dengan lingkup x-data.

Untungnya, Alpine mengekspose sistem untuk evaluasi ekspresi


JavaScript dengan sebuah API evaluate(), Ini adalah sebuah contoh:

Alpine.directive("log", (el, { expression }, { evaluate }) => {


// expression === 'message'

console.log(evaluate(expression));
});

Sekarang ketika Alpine menginisialisasi <div x-log...>, Alpine akan


mengambil ekspresi memasukkannya ke dalam direktif (“message” pada
kasus ini), dan mengevaluasinya dalam context dari komponen elemen
Alpine saat ini.

115
Introduksi reactivity

Membangun contoh x-log seperti sebelumnya, katakanlah kita ingin x-log


untuk log nilai dari message dan juga log jika nilai berubah.

Berikan contoh template berikut:

<div x-data="{ message: 'Hello World!' }">


<div x-log="message"></div>

<button @click="message = 'yolo'">Change</button>


</div>
Anda ingin “Hellow World!” di log pada awalnya, kemudian kita ingin “yolo”
di log setelah menekan tombol <button>.

Kita dapat menyesuaikan implementasi x-log dan memperkenalkan dua


API baru untuk mencapai ini: evaluateLater() dan effect()

Alpine.directive("log", (el, { expression }, { evaluateLater, effect }) => {


let getThingToLog = evaluateLater(expression);

effect(() => {
getThingToLog((thingToLog) => {
console.log(thingToLog);
});
});
});

Mari kita telusuri kode diatas baris demi baris.

let getThingToLog = evaluateLater(expression);

Disini, alih-alih secara langsung mengevaluasi message dan mengambil


hasilnya, Kita convert string ekspresi (“message”) ke dalam sebuah fungsi
JavaScript yang kita akan jalankan kapanpun. Jika anda akan
mengevaluasi ekspresi JavaScript lebih dari sekali, sangat
direkomendasikan untuk generate sebuah fungsi JavaScript pertama kali
dan menggunakannya daripada memanggil evaluate() secara
langsung. Alasan dibalik itu adalah proses untuk menafsirkan sebuah
string sebagai fungsi javascript sangat mahal dan harus dihindari ketika
tidak diperlukan.
116
effect(() => {
...
})

Dengan mengoper sebuah callback ke effect(), kita memberitahu Alpine


untuk menjalankan secepatnya, kemudian melacak dependensi apapun
yang digunakan (properti x-data seperti message pada kasus
kita). Sekarang segera setelah 1 dependency berubah callback ini akan
dijalankan ulang ini memberi kita “reactivity”.

Anda mungkin menyadari fungsi ini dari x-effect. Ini memiliki mekanisme
yang sama di belakang layar.

Anda mungkin juga menyadari bahwa Alpine.effect() ada dan heran


kenapa kita tidak menggunakannya di sini. Alasannya fungsi effect
disediakan melalui parameter method memiliki fungsional yang khusus
yang membersihkan dirinya sendiri ketika directive dihapus dari halaman
untuk alasan apapun.

Sebagai contoh, jika untuk beberapa alasan elemen dengan x-log


dihapus dari halaman, dengan menggunakan effect() alih-alih
menggunakan Alpine.effect() ketika properti message berubah, nilai tidak
lagi di di log ke console.

getThingToLog((thingToLog) => {
console.log(thingToLog);
});
Sekarang kita dapat memanggil getThingToLo yang jika anda panggil ulang
merupakan fungsi JavaScript versi aktual dari ekspresi string: “message”.

Anda mungkin berekspektasi getThingToCall() mengembalikan


hasilnya secara langsung, tapi alih-alih Alpine mensyaratkan anda untuk
mengoper sebuah callback untuk menerima hasil.

Alasan dari ini adalah untuk mendukung ekspresi asinkronus seperti await
getMessage(). Dengan mengoper sebuah callback “receiver”. Alih-alih
mendapatkan hasil secara langsung, anda ada diperbolehkan
menggunakan direktif untuk bekerja dengan ekspresi asinkronus.

Cleaning Up

117
Katakanlah anda butuh untuk mendaftarkan sebuah event listener dari
sebuah custom directive. Setelah direktif dihapus dari halaman untuk
alasan apapun, anda mungkin ingin menghapus event listener juga.

Alpine membuatnya mudah dengan menyediakan sebuah fungsi cleanup


ketika mendaftarkan directive custom.

Ini adalah sebuah contoh:

Alpine.directive("...", (el, {}, { cleanup }) => {


let handler = () => {};

window.addEventListener("click", handler);

cleanup(() => {
window.removeEventListener("click", handler);
});
});

Sekarang jika direktif dihapus dari elemen ini atau elemennya sendiri
dihapus, event listener akan dihapus juga.

Custom magics

Alpine memungkinkan anda untuk mendaftarkan sebuah custom “magic”


(properti atau method) menggunakan Alpine.magic(). Magic apapun yang
anda daftarkan tersedia ke semua aplikasi anda dengan an awalan $.

Method signature

Alpine.magic("[name]", (el, { Alpine }) => {});

Nama magic, nama “foo” untuk contoh akan di konsumsi


name
sebagai $foo

el DOM Element Magic yang terterpicu dari

Alpine objek Global Alpine

118
Magic Property

Ini adalah sebuah contoh dari magic helper “$now” yang memudahkan
untuk mendapat waktu saat ini di mana pun di Alpine:

Alpine.magic("now", () => {
return new Date().toLocaleTimeString();
});

<span x-text="$now"></span>;
Sekarang tag <span> akan berisi waktu saat ini, menyerupai sesuatu seperti
“12:00:00 PM”.

Seperti yang dapat anda lihat $now berperilaku seperti properti


statistik, tapi di belakang layar sebenarnya sebuah getter yang
mengevaluasi setiap kali properti diakses.

karena itu, anda dapat menerapkan “fungsi” magic dengan


mengembalikan sebuah fungsi dari getar.

Magic functions

Sebagai contoh, Jika anda ingin membuat fungsi magic $clipboard() yang
menerima sebuah string untuk meng-copy ke Clipboard, kita akan
mengimplementasikannya seperti ini:

Alpine.magic("clipboard", () => {
return (subject) => navigator.clipboard.writeText(subject);
});

<button @click="$clipboard('hello world')">Copy "Hello World"</button>

Sekarang pengaksesan $clipboard mengembalikan fungsi clipboard itu


sendiri, kita dapat segera memanggilnya dan mengoper sebuah
argumen seperti yang kita lihat di template dengan $clipboard('hello
world').

Anda dapat menggunakan syntax yang lebih singkat (sebuah double


arrow function) untuk mengembalikan sebuah fungsi dari sebuah fungsi
jika anda lebih suka:

119
Alpine.magic("clipboard", () => (subject) => {
navigator.clipboard.writeText(subject);
});

Writing and sharing plugins

Sampai saat ini anda seharusnya melihat betapa mudah dan


sederhananya mendaftarkan custom directive dan magic anda di aplikasi
anda, tapi bagaimana dengan sharing fungsi melalui NPM atau yang lain?

Anda dapat memulainya dengan package resmi Alpine “plugin-


blueprint”. Ini semudah meng clone repository dan menjalankan npm
install && npm run buil untuk mendapat otorisasi in plugin.

Untuk mendemonstrasikan proses, Ayo buat sebuah plugin Alpine dari


awal bernama Foo yang ada directive (x-foo) dan magic (x-foo).

Kita akan memulai membuat ini untuk konsumsi tag <script> sederhana di
Alpine. Lalu meningkatkannya ke sebuah modul untuk diimpor ke dalam
bundel:

Script include

Mari kita mulai secara terbalik dengan melihat bagaimana plugin kita
akan dimasukkan ke dalam sebuah project.

<html>
<script src="/js/foo.js" defer></script>
<script src="/js/alpine.js" defer></script>

<div x-data x-init="$foo()">


<span x-foo="'hello world'">
</div>
</html>

Perhatikan bagaimana script kita dimasukkan SEBELUM Alpine itu


sendiri. Ini penting, jika tidak, Alpine telah diinisialisasi ketika kita plugin
kita di muat.

Sekarang lihat ke dalam content /js/foo.js:

document.addEventListener('alpine:init', () => {
window.Alpine.directive('foo', ...)
120
window.Alpine.magic('foo', ...)
})
itu saja! membuat plugin untuk dimasukkan via tag script sangat
sederhana dengan Alpine.

Bundle module

Sekarang katakanlah anda ingin membuat plugin yang seseorang dapat


diinstal melalui NPM dan memasukkan kedalam bundel mereka.

Seperti contoh terakhir, kita akan memulainya dengan terbalik, memulai


dengan bagaimana plugin akan dikonsumsi:

import Alpine from "alpinejs";

import foo from "foo";


Alpine.plugin(foo);

window.Alpine = Alpine;
window.Alpine.start();

anda akan menyadari bahwa ada API baru di sini: Alpine.plugin(). Ini
adalah method Alpine yang berguna untuk expose dan mencegah
konsumen dari plugin anda dari harus mendaftar beberapa direktif dan
magic berbeda sendiri.

Sekarang lihat sumber dari plugin yang akan kita eksport dari foo

export default function (Alpine) {


Alpine.directive('foo', ...)
Alpine.magic('foo', ...)
}
Kini anda dapat melihat Alpine.plugin sangatlah sederhana. Plugin
menerima sebuah callback dan secepatnya memanggilnya ketika Alpine
global menyediakan sebuah parameter untuk digunakan di dalamnya.

Kemudian anda dapat memperluas Alpine sesuka anda.

Async
Alpine dibangun untuk mendukung fungsi asinkronus di banyak tempat ini
mendukung yang standar.

Sebagai contoh, katakanlah anda memiliki sebuah fungsi sederhana yang


dinamakan getLabel() yang anda gunakan sebagai input ke direktif x-text:
121
function getLabel() {
return "Hello World!";
}

<span x-text="getLabel()"></span>;
karena getLabel sinkronus, semua berfungsi seperti yang diperkirakan.

Sekarang, mari kita berpura-pura getLabel membuat sebuah network


request untuk mengambil tabel dan tidak mengembalikannya secara
seketika (asinkronus). Dengan membuat getLabel fungsi asinkronus, anda
dapat memanggilnya dari Alpine menggunakan syntax JavaScript await.

async function getLabel() {


let response = await fetch("/api/label");

return await response.text();


}
<span x-text="await getLabel()"></span>;

Selain itu, jika anda lebih suka memanggil method di dalam Alpine tanpa
diikuti tanda kurung, Anda dapat membiarkannya tanpa tanda kurung
dan Alpine akan mendeteksi fungsi yang disediakan sebagai fungsi
asinkronus dan menanganinya. Sebagai contoh:

<span x-text="getLabel"></span>;

CSP (content security policy)


Supaya Alpine dapat mengeksekusi string biasa dari atribut html sebagai
ekspresi JavaScript, sebagai contoh x-on:click="console.log()", Alpine
membutuhkan untuk bergantung pada sebuah utility yang yang yang
melanggar kebijakan keamanan konten “unsafe-eval”.

*di belakang layar, Alpine sebenarnya tidak menggunakan eval() sendiri


karena lambat dan bermasalah. Alih-alih menggunakan fungsi deklarasi,
yang lebih baik, tapi masih melanggar “unsafe-eval”.

Agar bisa mengakomodasi environment di mana content security policy


ini diperlukan, Alpine menawarkan sebuah alternatif yang tidak
melanggar “unsafe-eval” tapi memiliki sintak yang lebih dibatasi.

Installation
122
Seperti semua ekstensi Alpine, anda dapat memasukkan melalui tag
<script> atau module import:

Script tag

<html>
<script src="alpinejs/alpinejs-csp/cdn.js" defer></script>
</html>;

Module import

import Alpine from "@alpinejs/csp";

window.Alpine = Alpine;
window.Alpine.start();

Restrictions

Karena Alpine tidak lagi menafsirkan string sebagai JavaScript


biasa, maka harus diuraikan (parse) dan di construct oleh fungsi
javascript dari mereka secara manual.

Karena keterbatasan ini, anda harus menggunakan Alpine.data untuk


mendaftar objek x-data anda, dan harus mereferensikan property dan
method hanya dengan key saja.

Sebagai contoh, sebuah komponen inline seperti ini tidak akan berfungsi.

<!-- Bad -->


<div x-data="{ count: 1 }">
<button @click="count++">Increment</button>

<span x-text="count"></span>
</div>
Meskipun, memecah ekspresi ke dalam API eksternal, contoh berikut valid
dengan CSP build:

<!-- Good -->


<div x-data="counter">
<button @click="increment">Increment</button>

<span x-text="count"></span>
</div>

Alpine.data("counter", () => ({

123
count: 1,

increment() {
this.count++;
},
}));

*SELESAI*

Diterjemahkan oleh @hari_kun

124

Anda mungkin juga menyukai