How are existing reactive observables connected to Alpine.js?
The Dexie.js website lists a few examples with React and Svelte but how would I use Dexie.js liveQuery with Alpine.js? Is it as simple as passing the variable to x-data
?
You cannot pass directly a liveQuery
object to an Alpine.js property because it will lose reactivity. We need to create a small wrapper that updates Alpine.js data when a liveQuery
returns new data. Here I provide a small example that uses a products
table, the Alpine.js component just lists the products and there's a small form that can add new products to the DB.
Example database definition in db.js
:
import Dexie from 'dexie'
export const db = new Dexie('myDatabase')
db.version(1).stores({
products: '++id, name, color',
})
In main.js
we make db
and liveQuery
global:
import Alpine from 'alpinejs'
import { liveQuery } from "dexie"
window.liveQuery = liveQuery
import { db } from './db'
window.db = db
window.Alpine = Alpine
window.Alpine.start()
The example Alpine.js component:
<div x-data="productsComponent">
<div>
<input type="text" x-model="name" placeholder="Name" />
<input type="text" x-model="color" placeholder="Color" />
<button @click="add">Add product</button>
</div>
<div>
<h2>Products</h2>
<template x-for="p in products">
<div x-text="`ID: ${p.id} Name: ${p.name} Color: ${p.color}`"></div>
</template>
</div>
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('productsComponent', () => ({
products: [],
name: '',
color: '',
observe(dataName, observable) {
const subscription = observable.subscribe({
next: val => {this[dataName] = val}
})
},
init() {
this.observe('products', liveQuery(() => db.products.toArray()))
},
async add() {
const id = await db.products.add({
name: this.name,
color: this.color,
})
this.name = ''
this.color = ''
}
}))
})
</script>
In the observe
method we subscribe the specific liveQuery
event and update the Alpine.js data when it changes.