Reputation: 2715
I am trying to make a form to submit data to supabase (with nextjs 13).
I can submit a string input. I am trying to add a boolean field.
I have commented out the 'published' fields in this form. If I try using this approach, and enter any of 'true' 'TRUE' 0 1 'false' or 'FALSE' in the input field, I get no errors in the console (none of my error flags produce a result, and I cannot even console log the enter key having been pressed.
I have also tried using a checkbox as shown below. When I try, I get an error that says:
TypeError: Cannot read properties of undefined (reading 'published')
This error doesn't make sense to me because when I hover over feeds in this state handler, I get a list of the attributes on feeds (and published is a boolean attribute defined there, with a default value of false).
form:
"use client"
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'
import { useEffect, useState } from 'react'
import { addFeed } from "./actions/newFeedFormSubmit"
type Feeds = Database['public']['Tables']['feeds']['Row']
export default function Feed( {feed}: { feed: Feeds;} ) {
const [isPublished, setIsPublished] = useState(feed.published )
const action = async (formData: FormData) => {
const result = await addFeed(formData) // addTweet is a server action, define it in a separate file
if (result?.error) {
console.log(result.error.message)
} else {
console.log(" added successfully")
// resetting input field
}
}
const [feeds, setFeeds] = useState<any[]>([])
// Create a Supabase client configured to use cookies
const supabase = createClientComponentClient<Database>()
useEffect(() => {
const getFeeds = async () => {
// This assumes you have a `todos` table in Supabase. Check out
// the `Create Table and seed with data` section of the README 👇
// https://github.com/vercel/next.js/blob/canary/examples/with-supabase/README.md
const { data } = await supabase.from('feeds').select()
if (data) {
setFeeds(data)
}
}
getFeeds()
}, [supabase, setFeeds])
return (
<div>
<form
action={action}
>
<input name="title" className="bg-inherit" />
{/* <input name="published" className="bg-inherit" /> */}
<input
name="published"
className="cursor-pointer"
onChange={() => setIsPublished(isPublished)}
// onChange={(e) => toggle()}
type="checkbox"
checked={isPublished ? true : false}
/>
</form>
<pre>{JSON.stringify(feeds, null, 2)}</pre>
</div>
);
}
form action:
"use server"
import { revalidatePath } from "next/cache"
import { cookies } from "next/headers"
import { createServerActionClient } from "@supabase/auth-helpers-nextjs"
export const addFeed = async (formData: FormData) => {
const title = String(formData.get("title"))
const published = Boolean(formData.get("published"))
const supabase = createServerActionClient<Database>({ cookies })
const {
data: { user },
} = await supabase.auth.getUser()
if (!user) {
throw new Error("No user found")
}
if (!title) {
return { error: { message: "Please enter a title" } }
}
try {
const { error } = await supabase
.from("feeds")
.insert({ title, published, created_by: user.id })
if (error) throw new Error(error.message)
} catch (error) {
console.error(error)
}
revalidatePath("/")
}
This documentation doesn't tell me how to apply a radio button to match the boolean choice.
Can anyone show me how to use a boolean data type in a supabase form input?
NEXT ATTEMPT
Chat gpt4 has given me a solution that works to submit to supabase where a boolean attribute is included in the data being submitted, but it is not using server actions as shown in the nextjs documentation.
The form has:
"use client"
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
import { useEffect, useState } from 'react';
import { addFeed } from "./actions/newFeedFormSubmit";
type Feeds = Database['public']['Tables']['feeds']['Row'];
export default function Feed({ feed }: { feed: Feeds; }) {
const [isPublished, setIsPublished] = useState(feed?.published || false);
const [feeds, setFeeds] = useState<any[]>([]);
const handleFormSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget as HTMLFormElement);
try {
await addFeed(formData);
console.log("Feed added successfully");
// You can reset the form or redirect the user, etc. here
} catch (error) {
if (error && typeof error === 'object' && "message" in error) {
console.error("Error from server action:", error.message);
}
}
};
return (
<div>
<form onSubmit={handleFormSubmit}>
<input name="title" className="bg-inherit" />
<input
name="published"
className="cursor-pointer"
type="checkbox"
checked={isPublished}
onChange={() => setIsPublished(prev => !prev)}
/>
<button type="submit">Submit</button>
</form>
<pre>{JSON.stringify(feeds, null, 2)}</pre>
</div>
);
}
The form action has:
"use server"
import { revalidatePath } from "next/cache";
import { cookies } from "next/headers";
import { createServerActionClient } from "@supabase/auth-helpers-nextjs";
export const addFeed = async (formData: FormData) => {
const title = String(formData.get("title"));
const published = Boolean(formData.has("published")) && formData.get("published") === 'on';
const supabase = createServerActionClient<Database>({ cookies });
const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new Error("No user found");
if (!title) throw new Error("Please enter a title");
console.log("attempting to add feed", { title, published });
const { error } = await supabase.from("feeds").insert({ title, published, created_by: user.id });
if (error) throw new Error(error.message);
revalidatePath("/");
}
Can anyone help figuring out why I can't use server actions to submit a form (in the format shown in the nextjs documentation, if the form data includes a boolean attribute?
thank you
Upvotes: 4
Views: 1416
Reputation: 497
Using this Supabase documentation as a reference, I recommend leveraging server actions with forms to handle the submission of your data, including the boolean field. When submitting the form, the information will be sent to an async function as shown in the code below. I recommend using a normal form instead of Supabase UI, as illustrated in the following example.
import { cookies } from 'next/headers'
import { createServerActionClient } from '@supabase/auth-helpers-nextjs'
import { revalidatePath } from 'next/cache'
import type { Database } from '@/lib/database.types'
export const dynamic = 'force-dynamic'
export default async function NewTodo() {
const addTodo = async (formData: FormData) => {
'use server'
const title = formData.get('title')
const published = formData.get('published') === 'true'; // Convert to boolean
const supabase = createServerActionClient<Database>({ cookies })
await supabase.from('feeds').insert({ title, published })
revalidatePath('/')
}
return (
<form action={addTodo}>
<input name="title" />
<label>
Published:
<input type="radio" name="published" value="true" />Yes
<input type="radio" name="published" value="false" />No
</label>
</form>
)
}
This example demonstrates how you can use Next.js 13 server actions with forms to submit data, including boolean values, to Supabase. The form captures the 'published' field as a boolean using radio buttons. Upon submission, the data is sent to the addTodo
function, which inserts the values into the 'feeds' table in Supabase.
I want to note that I'm also fairly new to Next.js 13 and Supabase, but I hope this solution aligns with the documentation's guidance and helps you with your implementation. Feel free to use a normal form instead of Supabase UI, as recommended.
If you run into any issues or have more questions, just give me a shout! I'm still getting the hang of Next.js 13 and Supabase myself, but I'm here to help as much as I can!
Upvotes: 1