Created
November 18, 2024 03:38
-
-
Save maietta/50d6451131bc09176fd2ecfab17c43e7 to your computer and use it in GitHub Desktop.
Example Svelte 5 Real Estate Form
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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