fix(launcher): use $derived.by for session liveQueries to fix stale presentation/presenter data
When switching sessions within the same location, presentations and presenters
were not updating. The root cause: plain $derived(liveQuery(...)) never recreates
the Observable when slct__event_session_id changes, because liveQuery's async
callback runs in Dexie's zone where Svelte tracking is off. Dexie's range-level
change detection then ignores new session data (it arrives under a different
event_session_id index value, outside the originally observed range).
Replaced all four liveQuery declarations with $derived.by(() => { const id = ...;
return liveQuery(...id...); }) — the same pattern already used in +layout.svelte
for location-dependent queries. Svelte tracks the id read in the outer closure
and recreates the Observable on every session change.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -50,10 +50,17 @@ import {
|
|||||||
Users
|
Users
|
||||||
} from '@lucide/svelte';
|
} from '@lucide/svelte';
|
||||||
// Event Session (Main View Trigger)
|
// Event Session (Main View Trigger)
|
||||||
// WHY: We use a simple derived observable. The template handles the $ prefix.
|
// WHY: $derived.by captures the id in the outer closure so Svelte tracks it as a
|
||||||
let lq__event_session_obj = $derived(
|
// reactive dependency and recreates the Observable when slct__event_session_id changes.
|
||||||
liveQuery(() => db_events.session.get(slct__event_session_id))
|
// Plain $derived(liveQuery(...)) does NOT work here: liveQuery's async callback runs in
|
||||||
);
|
// Dexie's zone where Svelte tracking is off, so $derived never sees the id read and never
|
||||||
|
// recreates the Observable when the session changes. Dexie's range-level change tracking
|
||||||
|
// then keeps the stale Observable alive — it only re-fires when data in the originally
|
||||||
|
// observed key range changes, not when a different session's data arrives.
|
||||||
|
let lq__event_session_obj = $derived.by(() => {
|
||||||
|
const id = slct__event_session_id;
|
||||||
|
return liveQuery(() => db_events.session.get(id));
|
||||||
|
});
|
||||||
|
|
||||||
// WHY: type_code drives poster vs. oral UI branching throughout this component.
|
// WHY: type_code drives poster vs. oral UI branching throughout this component.
|
||||||
// It was previously a prop that was never passed by the parent, so all poster
|
// It was previously a prop that was never passed by the parent, so all poster
|
||||||
@@ -62,65 +69,63 @@ let lq__event_session_obj = $derived(
|
|||||||
let type_code = $derived($lq__event_session_obj?.type_code ?? '');
|
let type_code = $derived($lq__event_session_obj?.type_code ?? '');
|
||||||
|
|
||||||
// Event File (for a Session)
|
// Event File (for a Session)
|
||||||
// WHY: Pure data retrieval. Side effects (updating global stores) are removed
|
// WHY: $derived.by — same reason as lq__event_session_obj above. Without recreating
|
||||||
// to prevent circular reactivity loops during rapid navigation.
|
// the Observable when slct__event_session_id changes, Dexie never re-fires for the new
|
||||||
let lq__event_file_obj_li = $derived(
|
// session's files (they land in a different for_id range than what was originally observed).
|
||||||
liveQuery(async () => {
|
let lq__event_file_obj_li = $derived.by(() => {
|
||||||
if (!slct__event_session_id) return [];
|
const id = slct__event_session_id;
|
||||||
|
return liveQuery(async () => {
|
||||||
|
if (!id) return [];
|
||||||
|
|
||||||
if (log_lvl > 1) {
|
if (log_lvl > 1) {
|
||||||
console.log(
|
console.log(`[LQ] Fetching files for session: ${id}`);
|
||||||
`[LQ] Fetching files for session: ${slct__event_session_id}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return await db_events.file
|
return await db_events.file
|
||||||
.where('for_id')
|
.where('for_id')
|
||||||
.equals(slct__event_session_id)
|
.equals(id)
|
||||||
.reverse()
|
.reverse()
|
||||||
.sortBy('created_on');
|
.sortBy('created_on');
|
||||||
})
|
});
|
||||||
);
|
});
|
||||||
|
|
||||||
// Event Presentation
|
// Event Presentation
|
||||||
let lq__event_presentation_obj_li = $derived(
|
// WHY: $derived.by — same reason as above. Captures both id and sort_by in the outer
|
||||||
liveQuery(async () => {
|
// closure so a new Observable is created whenever the session or its type changes.
|
||||||
if (!slct__event_session_id) return [];
|
let lq__event_presentation_obj_li = $derived.by(() => {
|
||||||
|
const id = slct__event_session_id;
|
||||||
|
const sort_by = type_code == 'poster' ? 'name' : 'start_datetime';
|
||||||
|
return liveQuery(async () => {
|
||||||
|
if (!id) return [];
|
||||||
|
|
||||||
if (log_lvl > 1) {
|
if (log_lvl > 1) {
|
||||||
console.log(
|
console.log(`[LQ] Fetching presentations for session: ${id}`);
|
||||||
`[LQ] Fetching presentations for session: ${slct__event_session_id}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let sort_by = 'start_datetime';
|
|
||||||
if (type_code == 'poster') {
|
|
||||||
sort_by = 'name';
|
|
||||||
}
|
|
||||||
return await db_events.presentation
|
return await db_events.presentation
|
||||||
.where('event_session_id')
|
.where('event_session_id')
|
||||||
.equals(slct__event_session_id)
|
.equals(id)
|
||||||
.sortBy(sort_by);
|
.sortBy(sort_by);
|
||||||
})
|
});
|
||||||
);
|
});
|
||||||
|
|
||||||
// Event Presenter
|
// Event Presenter
|
||||||
let lq__event_presenter_obj_li = $derived(
|
// WHY: $derived.by — same reason as above.
|
||||||
liveQuery(async () => {
|
let lq__event_presenter_obj_li = $derived.by(() => {
|
||||||
if (!slct__event_session_id) return [];
|
const id = slct__event_session_id;
|
||||||
|
return liveQuery(async () => {
|
||||||
|
if (!id) return [];
|
||||||
|
|
||||||
if (log_lvl > 1) {
|
if (log_lvl > 1) {
|
||||||
console.log(
|
console.log(`[LQ] Fetching presenters for session: ${id}`);
|
||||||
`[LQ] Fetching presenters for session: ${slct__event_session_id}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return await db_events.presenter
|
return await db_events.presenter
|
||||||
.where('event_session_id')
|
.where('event_session_id')
|
||||||
.equals(slct__event_session_id)
|
.equals(id)
|
||||||
.sortBy('full_name');
|
.sortBy('full_name');
|
||||||
})
|
});
|
||||||
);
|
});
|
||||||
|
|
||||||
// let show_modal_upload_files: boolean = false;
|
// let show_modal_upload_files: boolean = false;
|
||||||
// let link_to_type: null|string = null;
|
// let link_to_type: null|string = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user