Package aiming to make it easier to manage data with advanced features in Svelte apps
Your tsconfig.json must be set to "moduleResolution": "bundler"
For scenarios when the native <select>
element does not suffice.
<form on:submit|preventDefault={onSubmit} style="width: 100%;">
<EnhancedSelect name="users" pool={users} values={[1, 3]} force multiple let:values let:pool>
<svelte:fragment slot="summary">
{@const filtered = pool.filter((user) => values.includes(user.id))}
<input type="text" readonly style="width: 100%" value={filtered.map((user) => user.username).join(", ")} />
</svelte:fragment>
<div class="selector">
{@const filtered = filterOptions(users)}
<input type="search" style="width: 100%" placeholder="Employee" name="name" />
<input type="search" style="width: 100%" placeholder="Employee" name="username" />
<EnhancedOption {registerOption} togglesAll>
<input tabindex="-1" type="checkbox" checked={allChecked} />
{#if allChecked}Uncheck all{:else}Check all{/if} ({filtered.length})
</EnhancedOption>
{#each filtered as user (user.id)}
<EnhancedOption {registerOption} value={user.id} item={user} let:checked
><input tabindex="-1" type="checkbox" {checked} />{user.name}</EnhancedOption>
{/each}
</div>
</EnhancedSelect>
<button type="submit">submit</button>
</form>
Handle pulling and pushing a value to and from a replication source
Name | Replication source |
---|---|
LocalStorageSyncer | window.localStorage |
SessionStorageSyncer | window.sessionStorage |
CookieSyncer | document.cookie |
Examples on how you can employ these components in different scenarios:
window.localStorage
import { LocalStorageSyncer } from "@maal/svelte-data/sync";
import { writable } from "svelte/store";
const syncer = new LocalStorageSyncer("key", "initialValue");
export const someStore = writable<string>(syncer.pull());
someStore.subscribe((value) => syncer.push(value));
Recommendation: For models, use classes. Not interfaces.
Reason: interfaces exist to tell TypeScript that "this object is guaranteed to have these members".
This is fine at build-time, but when dealing with data stored at various locations at runtime, we can't guarantee that.
Did the REST endpoint you are calling change? Did the user modify the data stored in localStorage? Was there a JSON property that could be null that your code has not accounted for?
All of these problems are dealt with when doing the following:
Response
is what you expect it to beimport { ensureArray } from "@maal/svelte-data/types";
Response.prototype.ensureSuccess = function (): Response {
if (!this.ok) {
throw new Error(`Expected status code indicating success, got: ${this.status} ${this.statusText}`);
}
return this;
};
export class TestHTTP {
public async getForecasts(): Promise<WeatherForecast[]> {
const res = await window.fetch("http://localhost:5173/api/weatherforecast");
return ensureArray(await res.ensureSuccess().json()).map((el) => new WeatherForecast(el));
}
}
import { ensureObject, ensureDateString, ensureNumber, ensureString } from "@maal/svelte-data";
export class WeatherForecast {
date: Date;
temperatureC: number;
temperatureF: number;
summary: string | null;
public constructor(something: unknown) {
const o = ensureObject(something);
this.date = ensureDateString(o.date);
this.temperatureC = ensureNumber(o.temperatureC);
this.temperatureF = ensureNumber(o.temperatureF);
this.summary = ensureString(o.summary);
}
}
Using HTTPClient
does these things for you:
import { HTTPClient } from "@maal/svelte-data/http";
import { WeatherForecast } from "$lib/models/WeatherForecast.js";
/** @static */
export class TestHTTP {
/** TODOC */
private static httpClient = new HTTPClient("http://localhost:5173/api/", { redirect: "manual", credentials: "include" });
/** @param fetch This is only needed for SSR */
public static async getForecasts(fetch?: typeof window.fetch): Promise<WeatherForecast[]> {
return await this.httpClient
.get("weatherforecast")
.withFetch(fetch) // If you are fetching server-side in SvelteKit's `load` function
.fromJSONArray((something) => new WeatherForecast(something));
}
}