Mel
Mel

Reputation: 2715

How to make a boolean form input in supabase using nextjs server actions?

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

Answers (1)

Vladimirzb
Vladimirzb

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.

Code 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>
  )
}

Explanation

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

Related Questions