Real-time updates
React to data changes with list.onResultChange() and push changes into dcupl with data.upsert().
Key dcupl functions
| Function | Purpose |
|---|---|
list.onResultChange() |
Run a callback when the list's result changes (returns unsubscribe function) |
dcupl.data.upsert() |
Add new items or update existing ones (staged) |
dcupl.data.remove() |
Remove data items (staged) |
dcupl.update() |
Apply staged data changes; affected lists emit result_updated |
Example data
The snippets up to the Complete Flow use this Product model:
import { Dcupl } from '@dcupl/core';
const dcupl = new Dcupl();
dcupl.models.set({
key: 'Product',
properties: [
{ key: 'name', type: 'string' },
{ key: 'stock', type: 'int' },
],
});
dcupl.data.set(
[
{ key: 'prod-1', name: 'Widget', stock: 50 },
{ key: 'prod-2', name: 'Gadget', stock: 100 },
{ key: 'prod-3', name: 'Gizmo', stock: 5 },
],
{ model: 'Product' },
);
await dcupl.init();Listening to list events
Subscribe to result changes on a list with list.onResultChange(). It fires once per
dcupl.update() that can have changed the list (also for an update with nothing staged), and when
the list's query changes — never for reads such as items():
const productList = dcupl.lists.create({ modelKey: 'Product' });
const unsubscribe = productList.onResultChange(() => {
// Refresh your UI here
console.log('Products:', productList.catalog.query.items());
});
// Later: cleanup
unsubscribe();list.on() receives every event of the list, including reads; filter on
event.type === 'result_updated' if you need it. See the Events reference.
A list created with a query option keeps the keys that query selected: after dcupl.update() it
serves their current values and removed items drop out, but a new match doesn't join it and an
item that stops matching stays. Call list.update() to re-run the query once, or give the list
autoUpdate: true (or set performance.autoUpdateLists.enabled) to re-run it on each
dcupl.update(); the Auto-Update Pattern shows how to pass
it in TypeScript.
Updating data with data.upsert()
Push new or updated items into dcupl. upsert() inserts unknown keys and updates existing items;
every attribute in the payload replaces the stored value, attributes you leave out keep theirs.
Don't use data.set() for this: it replaces all data of the model.
// Add a new item or update an existing one
dcupl.data.upsert([{ key: 'prod-4', name: 'Doohickey', stock: 20 }], { model: 'Product' });
// Apply changes
await dcupl.update();Update multiple items at once:
dcupl.data.upsert(
[
{ key: 'prod-1', stock: 45 },
{ key: 'prod-2', stock: 120 },
{ key: 'prod-3', stock: 0 },
],
{ model: 'Product' },
);
await dcupl.update();Removing data
Remove items by key:
dcupl.data.remove([{ key: 'prod-3' }], { model: 'Product' });
await dcupl.update();Complete flow
Combine event listening with data updates:
import { Dcupl } from '@dcupl/core';
const dcupl = new Dcupl();
dcupl.models.set({
key: 'Order',
properties: [{ key: 'status', type: 'string' }],
});
dcupl.data.set([], { model: 'Order' }); // Start empty
await dcupl.init();
const orderList = dcupl.lists.create({ modelKey: 'Order' });
// 1. Listen for changes
orderList.onResultChange(() => {
const orders = orderList.catalog.query.items();
console.log('Orders updated:', orders.length);
});
// 2. Add data (from your data source)
async function handleNewOrder(order: { key: string; status: string }) {
dcupl.data.upsert([order], { model: 'Order' });
await dcupl.update(); // orderList emits result_updated
}
// 3. Update existing item
async function updateOrderStatus(orderId: string, status: string) {
dcupl.data.update([{ key: orderId, status }], { model: 'Order' });
await dcupl.update();
}
// 4. Remove item
async function deleteOrder(orderId: string) {
dcupl.data.remove([{ key: orderId }], { model: 'Order' });
await dcupl.update();
}data.update() only changes items that already exist; an unknown key is ignored. Use upsert()
when the item may be new.
Batching updates
For multiple changes, call dcupl.update() once at the end:
// Queue multiple changes
dcupl.data.upsert([{ key: 'prod-1', stock: 10 }], { model: 'Product' });
dcupl.data.upsert([{ key: 'prod-2', stock: 20 }], { model: 'Product' });
dcupl.data.remove([{ key: 'prod-3' }], { model: 'Product' });
// A single update: each affected list emits result_updated once
await dcupl.update();