Skip to content

Instantly share code, notes, and snippets.

@maietta
Created November 18, 2024 03:38
Show Gist options
  • Save maietta/50d6451131bc09176fd2ecfab17c43e7 to your computer and use it in GitHub Desktop.
Save maietta/50d6451131bc09176fd2ecfab17c43e7 to your computer and use it in GitHub Desktop.
Example Svelte 5 Real Estate Form
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/stores';
import { onMount } from 'svelte';
import { queryParameters, ssp } from 'sveltekit-search-params';
import Pagination from './pagination.svelte';
let { records, ...props } = $props();
const system = $state({ Class: '', Type: '', page: 1 });
const form = queryParameters(
{
test: {
encode: (value) => (value && value.trim() ? value : undefined),
decode: (value) => (value && value.trim() ? value : undefined),
equalityFn: (a, b) => a === b
},
Area: {
encode: (value) => (value ? String(value) : undefined), // Convert to string for the URL
decode: (value) => (value ? parseInt(value, 10) : undefined) // Parse back as a number
},
Bedrooms: {
encode: (value) => (value ? String(value) : undefined), // Convert to string for the URL
decode: (value) => (value ? parseInt(value, 10) : undefined) // Parse back as a number
},
Bathrooms: {
encode: (value) => (value ? String(value) : undefined), // Convert to string for the URL
decode: (value) => (value ? parseInt(value, 10) : undefined) // Parse back as a number
},
page: ssp.number(1)
// pageSize: ssp.number(15)
},
{
pushHistory: false, // Enables updating the browser history
showDefaults: false, // Don't include default values in the query string
debounceHistory: 800
}
);
// Initialize values on mount
onMount(() => {
const [classSegment, typeSegment] = $page.params.slugs.split('/').filter(Boolean);
system.Class = classSegment || '';
system.Type = typeSegment || '';
const urlSearchParams = new URLSearchParams($page.url.searchParams);
for (const [key, value] of urlSearchParams.entries()) {
form[key] = value;
}
});
let previousUrl = '';
$effect(() => {
const url = buildUrl();
if (url !== previousUrl) {
previousUrl = url;
goto(url, { replaceState: true });
}
});
function buildUrl() {
let url = '/search';
if (system.Class) {
url += `/${encodeURIComponent(system.Class)}`;
if (system.Type) url += `/${encodeURIComponent(system.Type)}`;
}
const searchParams = new URLSearchParams($page.url.searchParams);
searchParams.set('page', '1');
return `${url}?${searchParams.toString()}`;
}
</script>
<form id="search" class="shadow-inset flex flex-col gap-4 rounded border bg-white p-4">
<label for="Class"><span class="font-bold">Property Type: </span></label>
<select name="Class" id="Class" bind:value={system.Class} class="border border-red-300">
<option value="">— choose a property type —</option>
<option value="residential">Traditional Residential</option>
<option value="multi-family">Multi-family Residential</option>
<option value="land">Lots and Land</option>
<option value="commercial">Commercial</option>
</select>
<input name="test" type="text" class="border border-red-300" bind:value={form.test} />
{#if form.Class === 'residential'}
<label for="Type"
><span class="font-bold">Residence Type: </span>
<select name="Type" id="Type" bind:value={system.Type} class="w-full">
<option value="">— any type of residential —</option>
<option value="single-family">Single Family Residence</option>
<option value="single-family-w-guest">Single Family w/Guest Addition(s)</option>
<option value="manufactured-on-land">Manufactured Residence on Land</option>
<option value="mobile-only">Mobile Only</option>
</select></label
>
<!-- Additional fields for Residential -->
<label for="bedrooms"><span class="font-bold">Bedrooms:</span></label>
<input
type="number"
bind:value={form.Bedrooms}
name="Bedrooms"
placeholder="Number of bedrooms"
/>
<label for="bathrooms"><span class="font-bold">Bathrooms:</span></label>
<input
type="number"
bind:value={form.Bathrooms}
name="Bathrooms"
placeholder="Number of bathrooms"
/>
{/if}
</form>
{#if props.data.records.length > 0}
<Pagination pagination={props.data.pagination} />
{#each props.data.records as record}
<p>{JSON.stringify(record, null, 2)}</p>
{/each}
<Pagination pagination={props.data.pagination} />
{:else}
<p>No results found. Broaden your search criteria.</p>
{/if}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment