# Load when a dialog opens

> A query that requests its data when the dialog opens, aborts when it closes and keeps the data for the next opening.

Page: https://svelte-lean.vercel.app/query/recipes/dialog · Markdown: https://svelte-lean.vercel.app/query/recipes/dialog.md · Index: https://svelte-lean.vercel.app/llms.txt

Create the query with the component and read it inside the dialog's {#if open}: the request starts when the dialog opens and stops when it closes.

## Example

Open a dialog, close it with Escape before the answer arrives, open it again.

```svelte
<!-- src/lib/members/MemberDialog.svelte -->
<script lang="ts">
	import { createQuery } from '@svelte-lean/query';
	import { getMember } from '$api/members';

	let { id, name }: { id: number; name: string } = $props();

	const uid = $props.id();
	let dialog = $state<HTMLDialogElement>();
	let open = $state(false);
	// Created now, requested only when `member` is read on screen.
	const member = createQuery(getMember, () => ({ id }));

	function show() {
		open = true;
		dialog?.showModal();
	}
</script>

<button type="button" onclick={show}>Details of {name}</button>

<dialog bind:this={dialog} onclose={() => (open = false)} aria-labelledby="{uid}-title">
	<h2 id="{uid}-title">{name}</h2>
	{#if open}
		{#if member.loading}
			<p>Loading…</p>
		{:else if member.error}
			<p role="alert">{member.error.message}</p>
		{:else if member.data}
			<p>{member.data.email} · {member.data.team} · {member.data.status}</p>
		{/if}
	{/if}
	<form method="dialog"><button>Close</button></form>
</dialog>
```

Three rows, each rendering the component shown. An in-memory server answers after a fixed delay.

`src/lib/api/members.ts`

```ts
export const getMember = defineQuery({
	get: 'api/members/{id}',
	result: type<Member>(),
	entity: 'Member',
	access: 'members.view'
});
```

## How it works

| Moment | Request | State |
| --- | --- | --- |
| The component mounts | none: `createQuery` creates no entry until it is read | `info.status: 'idle'` |
| The dialog opens | `GET api/members/1`, cause `mount` | `loading` |
| Closed before the answer | aborted; nothing is written | unchanged |
| Opened again, data cached | none while fresh, else a background refetch | data at once, then `refreshing` |
| Closed for longer than `keep` | the entry is collected; the next opening fetches | `loading` |

- The native `<dialog>` gives the modal, the focus trap, Escape and the return of focus; the component only tracks `open` from its `close` event.
- `$props.id()` gives each instance its own heading id for `aria-labelledby`.

## Variations

### Read outside the block

When the template reads the query outside `{#if open}` (a title, a count), `when` pauses it instead. Its data is kept while paused.

```ts
// Read outside {#if}: `when` pauses the query while the dialog is closed and keeps its data.
const member = createQuery(getMember, () => ({ id }), { when: () => open });
```

### Prepare before the click

`getMember.prefetch({ id })` on `pointerenter` fills the entry at low priority, so the dialog opens with data.

## Related

- [Reading](https://svelte-lean.vercel.app/query/reading.md): states, `when`, a missing input and `load()`.
- [Dependent queries](https://svelte-lean.vercel.app/query/recipes/dependent-queries.md)
- [Dialog](https://svelte-lean.vercel.app/primitives/dialog.md) primitive
