binajmen
binajmen
Explore posts from servers
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
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
SSolidJS
Created by binajmen on 10/3/2023 in #support
How to choose between Store and Context?
I've gathered that a store can reside in its own file and be imported in multiple locations, acting as a shared state. Given this, why would I opt for a context when a store seems capable of handling the task? Whether it's for theming or authentication status, a store seems apt. Is there an advantage to using a context, or some trade-offs or crucial factors I might be overlooking?
4 replies
SSolidJS
Created by binajmen on 9/29/2023 in #support
How do you consume server actions response?
It might look as a silly question, but it is unclear for me how you must consume the response (either is it result or error).
export default function Users() {
const users = useRouteData<typeof routeData>();

const [creating, { Form }] = createServerAction$(
async (formData: FormData) => {
await new Promise((resolve, reject) => setTimeout(resolve, 1000));
const email = String(formData.get("email"));

if (email.length < 10) {
return json({ success: false, fields: { email: "too small" } }); // <-- will end up in result
// throw json({ success: false, fields: { email: "too small" } }); // <-- will end up in error
}

await db.insert(usersTable).values({ email });

return json({ success: true });
}
);

createEffect(() => console.log("effect:", creating, creating.pending));
console.log(creating);

return (
<div>
<h1>Users list</h1>
<ul>
<For each={users()}>{(user) => <li>{user.email}</li>}</For>
</ul>
<Form>
<label for="email">Email:</label>
<input type="email" name="email" />
<Show when={creating.error}>Error: {creating.error/*???*/}</Show>
<input type="submit" value="submit" />
</Form>
</div>
);
}
export default function Users() {
const users = useRouteData<typeof routeData>();

const [creating, { Form }] = createServerAction$(
async (formData: FormData) => {
await new Promise((resolve, reject) => setTimeout(resolve, 1000));
const email = String(formData.get("email"));

if (email.length < 10) {
return json({ success: false, fields: { email: "too small" } }); // <-- will end up in result
// throw json({ success: false, fields: { email: "too small" } }); // <-- will end up in error
}

await db.insert(usersTable).values({ email });

return json({ success: true });
}
);

createEffect(() => console.log("effect:", creating, creating.pending));
console.log(creating);

return (
<div>
<h1>Users list</h1>
<ul>
<For each={users()}>{(user) => <li>{user.email}</li>}</For>
</ul>
<Form>
<label for="email">Email:</label>
<input type="email" name="email" />
<Show when={creating.error}>Error: {creating.error/*???*/}</Show>
<input type="submit" value="submit" />
</Form>
</div>
);
}
If the action failed (form validation, db error, etc.), I'd like to retrieve this info in the response. In the network tab, the result as the type Response (it makes sense). However, how am I suppose to consume the response and extract the JSON I'm sending from the action?
4 replies
SSolidJS
Created by binajmen on 7/12/2023 in #support
How to handle complex form?
10 replies
SSolidJS
Created by binajmen on 12/27/2022 in #support
Thrown ServerError are not catched by ErrorBoundary
Am I the only one impacted by this? https://github.com/solidjs/solid-start/issues/596
1 replies
SSolidJS
Created by binajmen on 12/23/2022 in #support
Incoherent data with multiple createServerData$ in routeData
With the following route:
export function routeData({ params }: RouteDataArgs) {
const members = createServerData$(
async (organisationId) => {
const members = await prisma.membership.findMany({
where: { organisationId },
include: { user: true },
});

return members.map((m) => ({ ...m, ...m.user }));
},
{ key: () => params.orgId }
);

const invitations = createServerData$(
(organisationId) =>
prisma.invitation.findMany({ where: { organisationId } }),
{ key: () => params.orgId }
);

return { members, invitations };
}

export default function ManageOrganisationMembers() {
const { members, invitations } = useRouteData<typeof routeData>();
const params = useParams();

console.log(JSON.stringify(members(), null, 2));
console.log(JSON.stringify(invitations(), null, 2));

return (
<Show when={members() && invitations()}>
<Header>Users</Header>
<Container>
<h1>Members</h1>
<Table
data={members()!}
...
/>
<h1 class="mt-10">Invitations</h1>
<Table
data={invitations()!}
...
/>
</Container>
</Show>
);
}
export function routeData({ params }: RouteDataArgs) {
const members = createServerData$(
async (organisationId) => {
const members = await prisma.membership.findMany({
where: { organisationId },
include: { user: true },
});

return members.map((m) => ({ ...m, ...m.user }));
},
{ key: () => params.orgId }
);

const invitations = createServerData$(
(organisationId) =>
prisma.invitation.findMany({ where: { organisationId } }),
{ key: () => params.orgId }
);

return { members, invitations };
}

export default function ManageOrganisationMembers() {
const { members, invitations } = useRouteData<typeof routeData>();
const params = useParams();

console.log(JSON.stringify(members(), null, 2));
console.log(JSON.stringify(invitations(), null, 2));

return (
<Show when={members() && invitations()}>
<Header>Users</Header>
<Container>
<h1>Members</h1>
<Table
data={members()!}
...
/>
<h1 class="mt-10">Invitations</h1>
<Table
data={invitations()!}
...
/>
</Container>
</Show>
);
}
I'm expecting an array of different objects for the members and the invitations. But when consoling/using the two data sets, invitations has the same content than members. If I change the declaration order in routeData, then members has the same content than invitations. Is this expected? Does that mean we can only have one createServerData$ in routeData?
2 replies
SSolidJS
Created by binajmen on 12/21/2022 in #support
Why useRouteData can return undefined?
In this example:
export function routeData({ params }: RouteDataArgs) {
return createServerData$(
async ([_, id], { request }) => {
const user = await authenticator.isAuthenticated(request, {
failureRedirect: "/",
});

if (!user.isAdmin) {
throw redirect("/login");
}

return prisma.organisation.findUniqueOrThrow({
where: { id },
});
},
{ key: () => ["organisation", params.orgId] }
);
}

export default function AdminOrganisations() {
const organisation = useRouteData<typeof routeData>();

return (
<>
<Header>{organisation().name}</Header>
<Container>...</Container>
</>
);
}
export function routeData({ params }: RouteDataArgs) {
return createServerData$(
async ([_, id], { request }) => {
const user = await authenticator.isAuthenticated(request, {
failureRedirect: "/",
});

if (!user.isAdmin) {
throw redirect("/login");
}

return prisma.organisation.findUniqueOrThrow({
where: { id },
});
},
{ key: () => ["organisation", params.orgId] }
);
}

export default function AdminOrganisations() {
const organisation = useRouteData<typeof routeData>();

return (
<>
<Header>{organisation().name}</Header>
<Container>...</Container>
</>
);
}
If I'm not an admin I'm redirected. If no organisation is found with the id, prisma throw. So I'm sure const organisation should be defined. But the type is still
const organisation: Resource<Organisation | undefined>
const organisation: Resource<Organisation | undefined>
Why?
12 replies
SSolidJS
Created by binajmen on 12/19/2022 in #support
i18n solid primitive with SolidStart
I'm in a snake biting its own tail situation. Using @solid-primitives/i18n, I'd like to use the /[lang]/... param to indicate I18nProvider which language to pick.
export default function Root() {
const params = useParams();

return (
<Html>
<Head>
...
</Head>
<Body>
<Suspense>
<ErrorBoundary>
<I18nProvider dict={dict} locale={params.lang}>
<Routes>
<FileRoutes />
</Routes>
</I18nProvider>
</ErrorBoundary>
</Suspense>
<Scripts />
</Body>
</Html>
);
}
export default function Root() {
const params = useParams();

return (
<Html>
<Head>
...
</Head>
<Body>
<Suspense>
<ErrorBoundary>
<I18nProvider dict={dict} locale={params.lang}>
<Routes>
<FileRoutes />
</Routes>
</I18nProvider>
</ErrorBoundary>
</Suspense>
<Scripts />
</Body>
</Html>
);
}
But I hit the error:
ReferenceError: navigator is not defined
at Proxy.createI18nContext (/Users/Projects/xyz/node_modules/@solid-primitives/i18n/dist/server.cjs:14:44)
ReferenceError: navigator is not defined
at Proxy.createI18nContext (/Users/Projects/xyz/node_modules/@solid-primitives/i18n/dist/server.cjs:14:44)
But useParams() returns undefined. Most probably not working outside <Routes>...
14 replies