เคยมั้ยที่อยากจะทำ Application ที่มีไม่เกิน 2–3 หน้า ไม่มี routing ที่ซับซ้อน มีเรียก API บ้าง ซึ่งปกติการที่จะขึ้น project ใหม่แบบนี้ ก็ต้องมีอย่างน้อย 2 projects คือ
- Web UI project อาจจะเป็น Vue.js, React.js หรือ Angular.js ก็ได้ ซึ่งผลลัพท์คือการ build เป็น static files เพื่อไปวางไว้ที่ hosting สักที่
- Api server จะเป็น Java, Go หรือ Node.js ก็ได้ แล้วเปิด CORS เพื่อ ให้หน้า Web สามารถเรียก Api ของเราได้
แต่บางทีเราก็อยากได้อะไรที่เล็กกว่านี้ เลยมาแนะนำ Alpine.js
เริ่มแบบง่ายๆกันเลย สามารถเรียกใช้จาก cdn ได้เลย เพราะ ไม่ต้อง build จ้า
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.3.5/dist/alpine.min.js" defer></script>
ตัวอย่างทั่วไป สามารถไปดูบนเว็บของเค้าได้เลย แต่เราจะโชว์การใช้จริงๆ คู่กับ fetch และ bulma css framework และ Event Bus
การ toggle modal ด้วย Event
โดยปกติแล้วการที่เราจะใช้ alpine js ที่ element ไหนก็ให้ประกาศ scope x-data ที่นั่น ///จำไว้ว่านี่ไม่ใช่ vue.js อย่าลืม ประกาศ scope x-data ก่อนใช้ด้วยหละ
<button class="button" x-data="{}" @click="$dispatch('show-modal')">Show</button>คือการที่เราประกาศ scope ภายในปุ่ม button จะทำให้สามารถเรียก @click ได้ ซึ่ง @click ในที่นี้ไม่ใช่ syntax ของ vue.js แต่อย่างใด แต่มันคือ syntax ของ alpine.js นั่นเอง (ลอก vue.js มาแปะๆเลย)
พอมีการเรื่องการประกาศ scope เข้ามา ทำให้การสื่อสารระหว่าง component (DOM element) ทำได้ยากเพราะ Alpine.js ไม่ support child parent scope
วิธีแรกที่ลองทำเลยก็คือ การประกาศ scope ใหญ่ scope เดียวที่ <body> เลยจร้า แต่ก็ทำให้รู้สึกว่าเราก็จะไม่ได้ใช้ข้อดีของการแยก scope ของ Alpine.js เลย สิ่งที่มาแก้ปัญหานี้ก็คือ Event Bus ซึ่งในที่นี้ $dispatch ก็คือการส่ง event ที่ชื่อ show-modal ออกไปนั่นเอง
ส่วนฝั่งรับ ก็คือ ฝั่ง modal ก็จะต้องประกาศ scope ของตัวเองเหมือนกัน
<div class="modal" x-data="{ 'show': false, submit: function() { console.log('submit') } }" :class="{ 'is-active': show }" x-on:show-modal.window="show = !show">
<div class="modal-background"></div>
<div class="modal-content">
<div class="box">
<div class="title has-text-centered">หน้าต่าง Modal</div>
<div class="field is-grouped">
<div class="control">
<button class="button is-link" @click="submit()">Update</button>
</div>
<div class="control">
<button class="button is-link is-light" @click="show = false">Cancel</button>
</div>
</div>
</div>
</div>
<button class="modal-close is-large" aria-label="close" @click="show = false"></button>
</div>
รับ Event โดย x-on:show-modal.window ก็คล้ายๆ v-on เปลี่ยนเป็น x-on 😜
การ add/remove class ก็ :class=”{ ‘is-active’: show }” ก็เหมือน Vue.js อีกแล้ววว
สักเกตุว่าภายใน scope เดียวกัน เราสามารถเรียกตัวแปร show ได้ทุกเมื่อ
Event with detail + fetch
เราสามารถเพิ่ม param ใน event ได้ตามนี้เลย
<button class="button" x-data="{}" @click="$dispatch('show-modal', { id: 1 })">Show</button>
ตอนรับสามารถเอาจาก $event.detail.id ซึ่งใน event เราสามารถเพิ่มให้ เรียก fetch data ก็ได้ สามารถใส่ code เพิ่มได้ตามนี้
x-on:show-modal.window="show = !show;
fetch('http://dummy.restapiexample.com/api/v1/employee/' + $event.detail.id)
.then(response => response.json())
.then((body) => {
name = body.data.employee_name
})
">
พอเราได้ data จากการ fetch มา ก็เก็บเข้าตัวแปรใน scope ได้เลย อย่าลืมไปประกาศตัวแปรใน x-data ด้วย
x-data="{ 'show': false, name: '' }"
เวลาเรียกใช้ x-text คือการ set ค่า innerHTML
<span x-text="name"></span>
Full code ตามนี้เลยจ้า