binajmen
binajmen
Explore posts from servers
SSolidJS
Created by binajmen on 2/15/2025 in #support
Using createAsync in SolidJS: Handling Data Dependencies
Currently, I'm thinking of two approaches: Unified Loader Pattern:
const loader = query(async (id: string) => {
"use server";
const criterion = await criterionRepo.find(id);
const programs = await programRepo.findAll();
const variants = await variantRepo.findByProgram(criterion.program_id);
return { criterion, programs, variants };
}, "admin-criterion");
const loader = query(async (id: string) => {
"use server";
const criterion = await criterionRepo.find(id);
const programs = await programRepo.findAll();
const variants = await variantRepo.findByProgram(criterion.program_id);
return { criterion, programs, variants };
}, "admin-criterion");
Separate Async Queries Pattern (commented out):
const criterion = createAsync(() => getCriterion(params.id));
const programs = createAsync(() => getPrograms());
const variants = createAsync(() => getVariantsByProgram(programId()));
const criterion = createAsync(() => getCriterion(params.id));
const programs = createAsync(() => getPrograms());
const variants = createAsync(() => getVariantsByProgram(programId()));
My key questions are: Data Loading Strategy Is it better to use a unified loader that fetches all related data in one query (similar to Remix's loader pattern), or should we use separate createAsync calls for each data dependency? Dynamic Data Updates How should we handle dynamic updates when a program is selected? Currently, the form has this select handler:
<Select
options={data()!.programs}
valueKey="id"
labelKey="name"
select={(program) => program.id === data()!.criterion.program_id}
onChange={(e) => setProgramId(e.currentTarget.value)}
/>
<Select
options={data()!.programs}
valueKey="id"
labelKey="name"
select={(program) => program.id === data()!.criterion.program_id}
onChange={(e) => setProgramId(e.currentTarget.value)}
/>
But changing the program doesn't update the variants because they're loaded once through the unified loader. Dependency Management The variants depend on the selected programId. The current loader handles this initial dependency well, but doesn't account for dynamic updates. Potential solutions: - Keep the loader for initial data but add a separate action/query for variant updates - Return to separate createAsync calls with proper dependency tracking - Implement a hybrid approach What's the most idiomatic way to handle this in SolidJS, considering both initial load and dynamic updates?
6 replies
SSolidJS
Created by binajmen on 1/28/2025 in #support
Why do I end up with a server-fns for a number input component?
I noticed in the build log these lines (see attachment). I do not understand why I have the InputNumber component in the server fns assets: .vinxi/build/server-fns/_server/number-input.mjs 0.90 kB This is the component itself:
import { Show, splitProps, type ComponentProps } from "solid-js";
import { Input } from "./input";

interface NumberInputProps
extends Omit<ComponentProps<typeof Input>, "onChange"> {
suffix?: string;
range?: [number, number];
onChange?: (value: number) => void;
}

export function NumberInput(props: NumberInputProps) {
const [local, others] = splitProps(props, ["suffix", "onChange"]);
let ref!: HTMLInputElement;

function parse(input: string) {
let number = Number.parseFloat(input.replace(",", "."));

if (Number.isNaN(number)) {
console.error("Invalid number format");
ref.value = String(0);
return;
}

if (props.range) {
const [min, max] = props.range;
number = Math.max(min, Math.min(max, number));
}

ref.value = String(number);
local.onChange?.(number);
}

return (
<div class="flex items-center gap-2">
<Input
{...others}
ref={ref}
type="text"
inputmode="decimal"
pattern="[\+\-]?[0-9]*[.,]?[0-9]+([eE][\+\-]?[0-9]+)?"
onChange={(e) => parse(e.currentTarget.value)}
/>
<Show when={local.suffix}>
<span class="text-gray-500 pointer-events-none">{local.suffix}</span>
</Show>
</div>
);
}
import { Show, splitProps, type ComponentProps } from "solid-js";
import { Input } from "./input";

interface NumberInputProps
extends Omit<ComponentProps<typeof Input>, "onChange"> {
suffix?: string;
range?: [number, number];
onChange?: (value: number) => void;
}

export function NumberInput(props: NumberInputProps) {
const [local, others] = splitProps(props, ["suffix", "onChange"]);
let ref!: HTMLInputElement;

function parse(input: string) {
let number = Number.parseFloat(input.replace(",", "."));

if (Number.isNaN(number)) {
console.error("Invalid number format");
ref.value = String(0);
return;
}

if (props.range) {
const [min, max] = props.range;
number = Math.max(min, Math.min(max, number));
}

ref.value = String(number);
local.onChange?.(number);
}

return (
<div class="flex items-center gap-2">
<Input
{...others}
ref={ref}
type="text"
inputmode="decimal"
pattern="[\+\-]?[0-9]*[.,]?[0-9]+([eE][\+\-]?[0-9]+)?"
onChange={(e) => parse(e.currentTarget.value)}
/>
<Show when={local.suffix}>
<span class="text-gray-500 pointer-events-none">{local.suffix}</span>
</Show>
</div>
);
}
This feels wrong. Am I misinterpreting the build output logs? What should I search to understand what is happening?
5 replies
SSolidJS
Created by binajmen on 1/7/2025 in #support
`useSession()` unexpectedly changing
No description
4 replies
DTDrizzle Team
Created by binajmen on 12/6/2024 in #help
How to access JSON nested value within a `select()`
Having this schema:
type Breakdown = {
land: number;
construction: number;
other: number;
};

export const table = mysqlTable("table", {
id: varchar("id", { length: 32 }).primaryKey(),
...
debt: json("debt")
.$type<Breakdown>()
.default({ land: 0, construction: 0, other: 0 })
.notNull(),
type Breakdown = {
land: number;
construction: number;
other: number;
};

export const table = mysqlTable("table", {
id: varchar("id", { length: 32 }).primaryKey(),
...
debt: json("debt")
.$type<Breakdown>()
.default({ land: 0, construction: 0, other: 0 })
.notNull(),
I would like to access debt values to compute the total in the select():
return db.select({
...getTableColumns(table),
debt_total: table.debt.land + table.debt.construction + table.land.other,
})...
return db.select({
...getTableColumns(table),
debt_total: table.debt.land + table.debt.construction + table.land.other,
})...
It does not seem possible as the moment or did I miss something?
3 replies
SSolidJS
Created by binajmen on 11/27/2024 in #support
IoC and support for decorators
Sooo, I was trying to play with inversify to create a light DDD template around SolidStart, but after my first try, I ended up with tons of error. From what I understand, h3 does not support decorators at the moment. I tried to install some babel plugins, without success. Did someone succeeded to use IoC with (or without) decorators? What is your technique?
1 replies
SSolidJS
Created by binajmen on 11/1/2024 in #support
`classList` does not seem to apply the classes on render
Here a reduced reproduction of the issue: https://playground.solidjs.com/anonymous/ba014c69-d95a-4e45-91cd-f95af6293f37 The issue: present should be underline. only when you click on past then present, then the classList is correctly applied I suspect my Button component should do something different regarding the class/classList. I'm not sure what... Any help would be greatly appreciated 🙏
4 replies
SSolidJS
Created by binajmen on 7/19/2024 in #support
is it ok to use `action()` to handle form submission in a SPA?
my idea is to handle form submission as follow:
...

const submit = action(async (formData: FormData) => {
const values = Object.fromEntries(formData.entries());
const parsing = projectSchema.safeParse(values);

if (!parsing.success) return parsing.error.flatten();

searchParams.id
? update.mutate({ ...parsing.data, id: searchParams.id })
: create.mutate(parsing.data);
});

const submission = useSubmission(submit);

return (
<Stack>
<h1 class="h1">Project</h1>
<form method="post" action={submit} class={stack()}>
<Input
name="name"
label="Projektbezeichnung"
value={project.data?.name}
error={submission.result?.fieldErrors?.name}
/>
...

const submit = action(async (formData: FormData) => {
const values = Object.fromEntries(formData.entries());
const parsing = projectSchema.safeParse(values);

if (!parsing.success) return parsing.error.flatten();

searchParams.id
? update.mutate({ ...parsing.data, id: searchParams.id })
: create.mutate(parsing.data);
});

const submission = useSubmission(submit);

return (
<Stack>
<h1 class="h1">Project</h1>
<form method="post" action={submit} class={stack()}>
<Input
name="name"
label="Projektbezeichnung"
value={project.data?.name}
error={submission.result?.fieldErrors?.name}
/>
but i'm wondering if there is a side effect i'm unaware of when in SPA mode 🤔 i believe actions were created for the SSR world, but perhaps i'm wrong and this usage is fine.
1 replies
SSolidJS
Created by binajmen on 7/4/2024 in #support
Is there a way to access children props?
Ih this code:
import { render, Dynamic } from "solid-js/web";
import { children, type ParentProps, For, createEffect } from "solid-js";

function App() {
return (
<Editor>
<Line>First line</Line>
<Line onClick={() => console.log("hey!")}>Second line</Line>
</Editor>
);
}

function Editor(props: ParentProps) {
const lines = children(() => props.children);

return (
<ol>
<For each={lines.toArray()}>
{(child, index) => <Dynamic component={Line} number={index() + 1} />}
</For>
</ol>
);
}

function Line(props: ParentProps<{ number?: number; onClick?: () => void }>) {
return (
<div onClick={() => props.onClick}>
{props.number} - {props.children}
</div>
);
}

render(() => <App />, document.getElementById("app")!);
import { render, Dynamic } from "solid-js/web";
import { children, type ParentProps, For, createEffect } from "solid-js";

function App() {
return (
<Editor>
<Line>First line</Line>
<Line onClick={() => console.log("hey!")}>Second line</Line>
</Editor>
);
}

function Editor(props: ParentProps) {
const lines = children(() => props.children);

return (
<ol>
<For each={lines.toArray()}>
{(child, index) => <Dynamic component={Line} number={index() + 1} />}
</For>
</ol>
);
}

function Line(props: ParentProps<{ number?: number; onClick?: () => void }>) {
return (
<div onClick={() => props.onClick}>
{props.number} - {props.children}
</div>
);
}

render(() => <App />, document.getElementById("app")!);
I was hoping to be able to pass the children props to the dynamic component. Is there a way to do this?
45 replies
SSolidJS
Created by binajmen on 6/10/2024 in #support
How to set a new value in a store of `Record<string, __>`?
In the following example: https://playground.solidjs.com/anonymous/07b233f7-59cb-4202-a3ca-595a497912f8 setValue("abc", 3) on a blank object will trigger an error:
Uncaught TypeError: Cannot read properties of undefined (reading 'output')
Uncaught TypeError: Cannot read properties of undefined (reading 'output')
Probably because the internal of the Store's path syntax function is trying to access the data. Am I suppose to use the Immer inspired produce to add a new element to an object, or is there a syntax I don't know to use directly the setter from the store without using produce?
10 replies
SSolidJS
Created by binajmen on 6/6/2024 in #support
Yet another reactivity problem :cry:
Hi, This is a small reproduction of a problem I have with reactivity. https://playground.solidjs.com/anonymous/ea30129e-e6d3-45aa-9345-192095a33f1b My main question is why the DOM is not updated whereas I return from the context a getter function (that should trigger the reactivity, right?) while the data is correctly logged in the console I based myself on this example: https://github.com/solidjs/solid-realworld/blob/f6e77ecd652bf32f0dc9238f291313fd1af7e98b/src/store/index.js#L17-L31
12 replies
SSolidJS
Created by binajmen on 5/20/2024 in #support
How do you delete an entry in an array when using `createStore`
In the following documentation, this case is not presented: https://docs.solidjs.com/guides/complex-state-management It could be trivial but I'm unsure of the right way for doing that 🙏
46 replies
SSolidJS
Created by binajmen on 4/30/2024 in #support
Is this (completely 🫣) illegal in Solid world?
what is the best primitives/library to use when dealing with deep nested structure? the data I'm dealing with looks like a graph with nodes and leaves. every nodes/leaves has a component that should update his data that should stay reactive. pretty hard to explain the context 😅 I was thinking about using a createStore (globally or within a context)
23 replies
SSolidJS
Created by binajmen on 4/26/2024 in #support
Are store reactive?
const [params, setParams] = createStore<Params>(
props.value ?? {
data: [
{ points: 100, requirement: 10 },
{ points: 50, requirement: 5 },
{ points: 0, requirement: 0 },
],
},
);

createEffect(() => {
console.log(params.data.at(0));
});
const [params, setParams] = createStore<Params>(
props.value ?? {
data: [
{ points: 100, requirement: 10 },
{ points: 50, requirement: 5 },
{ points: 0, requirement: 0 },
],
},
);

createEffect(() => {
console.log(params.data.at(0));
});
It consoles several time at rendering, but when modifying the values no more logs
17 replies
SSolidJS
Created by binajmen on 4/20/2024 in #support
Is conditional rendering possible?
I have the following code:
export default function Upsert() {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const program = getProgram(() => searchParams.id);
const mutation = postProgram(() => {
navigate("/admin/programs");
});

const [, { Form, Field }] = createForm<Program>({
validate: valiForm(programSchema),
initialValues: program.data,
});

return (
<Stack>
<h1 class="h1">Create program</h1>
<Form onSubmit={(values) => mutation.mutate(values)}>
<Stack>
<Field name="name">
{(field, props) => (
<TextField
{...field}
{...props}
label="Name"
error={merge(field, mutation)}
/>
)}
</Field>
<Button type="submit" class="self-start">
Create
</Button>
</Stack>
</Form>
</Stack>
);
}
export default function Upsert() {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const program = getProgram(() => searchParams.id);
const mutation = postProgram(() => {
navigate("/admin/programs");
});

const [, { Form, Field }] = createForm<Program>({
validate: valiForm(programSchema),
initialValues: program.data,
});

return (
<Stack>
<h1 class="h1">Create program</h1>
<Form onSubmit={(values) => mutation.mutate(values)}>
<Stack>
<Field name="name">
{(field, props) => (
<TextField
{...field}
{...props}
label="Name"
error={merge(field, mutation)}
/>
)}
</Field>
<Button type="submit" class="self-start">
Create
</Button>
</Stack>
</Form>
</Stack>
);
}
getProgram and postProgram are wrappers around solid-query. When accessing the page with an id in the query string (eg. ?id=123) the first time, initialValues equals to undefined as the query is not yet finished and program.data is undefined. Then the query resolved and now program.data is populated, but the form is already rendered so the form does not have any default values. Hitting a second time the same page with the same id will lead to a populated form: the cache is already present so this time program.data is defined. Is it possiple to trigger a re-rendering à la React - (don't shoot me 🙈 ) - to rerun createForm with the actual data? Or should I extract the createForm + <Form /> is a separate component and wrap it with a conditional <Show />?
22 replies
SSolidJS
Created by binajmen on 4/17/2024 in #support
How do you keep reactivity?
I'm trying to organize my code but I lose the reactivity on the way... When the searchParams.id value is set from undefined to a correct string value, I would expect the query to be executed and the effect to be triggered. It is not. If I uncomment the createQuery section instead of using getProgram, it works.
// ~/api/programs.ts
export function getProgram(id?: string) {
return createQuery<Program>(() => ({
queryKey: ["program", id],
queryFn: async () => {
return fetch(`http://localhost:4000/api/programs/${id}`)
.then((res) => res.json())
.then((data) => data.data);
},
enabled: !!id,
}));
}

-------------

import { getProgram, postProgram } from "~/api/programs";

export default function Upsert() {
const [searchParams, setSP] = useSearchParams();
const category = getProgram(searchParams.id);
// const category = createQuery<Program>(() => ({
// queryKey: ["program", searchParams.id],
// queryFn: async () => {
// return fetch(`http://localhost:4000/api/programs/${searchParams.id}`)
// .then((res) => res.json())
// .then((data) => data.data);
// },
// enabled: !!searchParams.id,
// }));

createEffect(() => {
console.log(
category,
category.data,
searchParams.id,
);
});
// ~/api/programs.ts
export function getProgram(id?: string) {
return createQuery<Program>(() => ({
queryKey: ["program", id],
queryFn: async () => {
return fetch(`http://localhost:4000/api/programs/${id}`)
.then((res) => res.json())
.then((data) => data.data);
},
enabled: !!id,
}));
}

-------------

import { getProgram, postProgram } from "~/api/programs";

export default function Upsert() {
const [searchParams, setSP] = useSearchParams();
const category = getProgram(searchParams.id);
// const category = createQuery<Program>(() => ({
// queryKey: ["program", searchParams.id],
// queryFn: async () => {
// return fetch(`http://localhost:4000/api/programs/${searchParams.id}`)
// .then((res) => res.json())
// .then((data) => data.data);
// },
// enabled: !!searchParams.id,
// }));

createEffect(() => {
console.log(
category,
category.data,
searchParams.id,
);
});
11 replies
SSolidJS
Created by binajmen on 4/12/2024 in #support
The props are reactive, right?
I've created a small wrapper around solid-table:
export function DataTable<TData extends { id: string }>(props: {
data: TableOptions<TData>["data"];
columns: TableOptions<TData>["columns"];
}) {
// const [data, setData] = createSignal(props.data);
const table = createSolidTable({
data: props.data,
// data: data(),
columns: props.columns,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getRowId: (row) => row.id,
});

createEffect(() => console.log(props.data));

// createEffect(() => setData(props.data));
// createEffect(() => console.log(data()));
export function DataTable<TData extends { id: string }>(props: {
data: TableOptions<TData>["data"];
columns: TableOptions<TData>["columns"];
}) {
// const [data, setData] = createSignal(props.data);
const table = createSolidTable({
data: props.data,
// data: data(),
columns: props.columns,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getRowId: (row) => row.id,
});

createEffect(() => console.log(props.data));

// createEffect(() => setData(props.data));
// createEffect(() => console.log(data()));
I use this component within a Suspense. Therefore props.data is equal to [], then populated with data. However, it doesn't seem to trigger an update. I tried to use a signal in the middle to make it reactive (see the comments) even if props.data is already reactive. The effects are triggered and logging the data, but the table remains empty 🤔
21 replies
SSolidJS
Created by binajmen on 4/11/2024 in #support
Am I obliged to combine Suspense with Show?
I get the following error: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'map') I understand the cause, but I'm surprised. I was expecting that the Suspense would delay the children until the data is available. Adding a Show solves the issue, but I'm wondering if I can handle this differently.
import { createQuery } from "@tanstack/solid-query";
import { Suspense } from "solid-js";

type Program = {
id: string;
name: string;
};

export default function List() {
const categories = createQuery<Program[]>(() => ({
queryKey: ["programs"],
queryFn: async () => {
return fetch("http://localhost:4000/api/programs")
.then((res) => res.json())
.then((data) => data.data);
},
}));

return (
<div>
<h1>Programs</h1>
<Suspense fallback={<p>Loading...</p>}>
{JSON.stringify(categories.data!.map((c) => c.name))}
</Suspense>
</div>
);
}
import { createQuery } from "@tanstack/solid-query";
import { Suspense } from "solid-js";

type Program = {
id: string;
name: string;
};

export default function List() {
const categories = createQuery<Program[]>(() => ({
queryKey: ["programs"],
queryFn: async () => {
return fetch("http://localhost:4000/api/programs")
.then((res) => res.json())
.then((data) => data.data);
},
}));

return (
<div>
<h1>Programs</h1>
<Suspense fallback={<p>Loading...</p>}>
{JSON.stringify(categories.data!.map((c) => c.name))}
</Suspense>
</div>
);
}
22 replies
DTDrizzle Team
Created by binajmen on 3/19/2024 in #help
Store percentage value as integer
Hi, I realised once again how awesome Drizzle is! I want to store percentage value as integer. I ended up with this:
export const percentage = customType<{ data: number, driverData: number }>({
dataType() {
return 'integer'
},
toDriver(value: number) {
return Math.round(value * 100)
},
fromDriver(value: number) {
return value / 100
}
})
export const percentage = customType<{ data: number, driverData: number }>({
dataType() {
return 'integer'
},
toDriver(value: number) {
return Math.round(value * 100)
},
fromDriver(value: number) {
return value / 100
}
})
For my use case, it is correct as I don't want to store more than 2 decimals. Using the type decimal is inconvenient as it is stored as string with the Postgres driver. Hence this choice. But my question is about the caveats of this technique. Does the in & out conversion affect the performance in a noticeable way?
3 replies
SSolidJS
Created by binajmen on 2/14/2024 in #support
ReferenceError on something that should (and DO) exist
tl;dr: getting a reference error on an existing (declared and in scope) variable:
categories.tsx:33 Uncaught ReferenceError: categories is not defined
at get when (categories.tsx:33:20)
at Switch.createMemo.equals.equals [as fn] (chunk-DIOA272S.js?v=36072530:1608:28)
at runComputation (chunk-DIOA272S.js?v=36072530:800:22)
at updateComputation (chunk-DIOA272S.js?v=36072530:782:3)
at createMemo (chunk-DIOA272S.js?v=36072530:344:10)
at Switch (chunk-DIOA272S.js?v=36072530:1604:22)
at chunk-DIOA272S.js?v=36072530:647:12
at untrack (chunk-DIOA272S.js?v=36072530:536:12)
at Object.fn (chunk-DIOA272S.js?v=36072530:643:37)
at runComputation (chunk-DIOA272S.js?v=36072530:800:22)
categories.tsx:33 Uncaught ReferenceError: categories is not defined
at get when (categories.tsx:33:20)
at Switch.createMemo.equals.equals [as fn] (chunk-DIOA272S.js?v=36072530:1608:28)
at runComputation (chunk-DIOA272S.js?v=36072530:800:22)
at updateComputation (chunk-DIOA272S.js?v=36072530:782:3)
at createMemo (chunk-DIOA272S.js?v=36072530:344:10)
at Switch (chunk-DIOA272S.js?v=36072530:1604:22)
at chunk-DIOA272S.js?v=36072530:647:12
at untrack (chunk-DIOA272S.js?v=36072530:536:12)
at Object.fn (chunk-DIOA272S.js?v=36072530:643:37)
at runComputation (chunk-DIOA272S.js?v=36072530:800:22)
The best is to check this reproductible example: https://stackblitz.com/github/binajmen/budget?file=src%2Fpages%2Fcategories.tsx I'm pretty sure I'm doing something wrong, but I can't figure out what..
2 replies
SSolidJS
Created by binajmen on 1/5/2024 in #support
How to Inform children of the active status of it's parent <A/>
I'm looking at something like:
<A href=".." class=".." activeClass="..">
{({ active }) =>
<span classList={{ "my-class": active }}>..</span>
}
</A>
<A href=".." class=".." activeClass="..">
{({ active }) =>
<span classList={{ "my-class": active }}>..</span>
}
</A>
3 replies