Server Action to get array of checkboxes?
Answered
West African Lion posted this in #help-forum
West African LionOP
This is my code:
I want
I am using Flowbite React for the checkbox component.
<div className="flex gap-8">
{tags.map((tag) => {
return (
<div
className="flex items-center gap-2 over flex-wrap-reverse my-4"
key={tag}
>
<Checkbox id={tag} name="tags" value={tag} />
<Label htmlFor={tag}>{tag}</Label>
</div>
);
})}
</div>I want
console.log(formData.get("tags")) to return an array of the checked options. Is that possible?I am using Flowbite React for the checkbox component.
28 Replies
@joulev try `formData.getAll("tags")`
West African LionOP
That did it! Was it in their docs? Did I miss it?
This is the server action, but it isn't displaying the new data until I manually refresh. Should I do something other than
Should I be returning the data object?
This is the server action, but it isn't displaying the new data until I manually refresh. Should I do something other than
redirect('/')?export async function createNote(formData: FormData) {
const supabase = createClient();
const title = formData.get("title") as string
const content = formData.get("content") as string
const tags = formData.getAll("tags") as Database["public"]["Enums"]["Note Tags"][]
const { data, error } = await supabase
.from('notes')
.insert([{ content, title, tags }])
.select()
redirect('/')
}Should I be returning the data object?
@West African Lion That did it! Was it in their docs? Did I miss it?
This is the server action, but it isn't displaying the new data until I manually refresh. Should I do something other than `redirect('/')`?
ts
export async function createNote(formData: FormData) {
const supabase = createClient();
const title = formData.get("title") as string
const content = formData.get("content") as string
const tags = formData.getAll("tags") as Database["public"]["Enums"]["Note Tags"][]
const { data, error } = await supabase
.from('notes')
.insert([{ content, title, tags }])
.select()
redirect('/')
}
Should I be returning the data object?
that formdata is the same formdata as this one https://developer.mozilla.org/en-US/docs/Web/API/FormData
you should run
you should run
revalidatePath/revalidateTag in that server action to get new data.@joulev that formdata is the same formdata as this one <https://developer.mozilla.org/en-US/docs/Web/API/FormData>
you should run `revalidatePath`/`revalidateTag` in that server action to get new data.
West African LionOP
I see! I think I understand. I was just following what they did here:
https://youtu.be/mwNZ34sxIGw?t=254
Does this seem like a reasonably structured?
I was running into a few issues with the
https://youtu.be/mwNZ34sxIGw?t=254
Does this seem like a reasonably structured?
"use client"
const notes = ({
notes,
}: {
notes: Database["public"]["Tables"]["notes"]["Row"][];
}) => {
return (
<Accordion className="w-96">
{notes.map((note) => (
<AccordionPanel key={note.id}>
<AccordionTitle>{note.title}</AccordionTitle>
<AccordionContent>
<div>{note.content}</div>
<div>Tags: {note.tags?.join(", ")}</div>
<Button onClick={() => deleteNote(note)}>Delete</Button>
</AccordionContent>
</AccordionPanel>
))}
</Accordion>
);
};"use server"
export async function deleteNote(note: Database["public"]["Tables"]["notes"]["Row"]) {
const supabase = createClient();
const { data, error } = await supabase
.from('notes')
.delete()
.eq('id', note.id)
revalidatePath('/')
}I was running into a few issues with the
"use server" and a button since I am now aware that an event handler is different from actionWest African LionOP
In that video, I see that the emoji is removed from the input but I went over the GitHub code and I can't see where that is coming from.
@West African Lion I see! I think I understand. I was just following what they did here:
https://youtu.be/mwNZ34sxIGw?t=254
Does this seem like a reasonably structured?
tsx
"use client"
const notes = ({
notes,
}: {
notes: Database["public"]["Tables"]["notes"]["Row"][];
}) => {
return (
<Accordion className="w-96">
{notes.map((note) => (
<AccordionPanel key={note.id}>
<AccordionTitle>{note.title}</AccordionTitle>
<AccordionContent>
<div>{note.content}</div>
<div>Tags: {note.tags?.join(", ")}</div>
<Button onClick={() => deleteNote(note)}>Delete</Button>
</AccordionContent>
</AccordionPanel>
))}
</Accordion>
);
};
ts
"use server"
export async function deleteNote(note: Database["public"]["Tables"]["notes"]["Row"]) {
const supabase = createClient();
const { data, error } = await supabase
.from('notes')
.delete()
.eq('id', note.id)
revalidatePath('/')
}
I was running into a few issues with the `"use server"` and a button since I am now aware that an event handler is different from `action`
yeah looks good, though i'd do wrap the <Button> in a form and use a form action [with
* you have access to
* you can use
* it works with js disabled (progressive enhancement)
.bind to bind the note variable](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#passing-additional-arguments) instead. it has some benefits over simply calling the action:* you have access to
useFormStatus, no longer having to handle loading state manually for example* you can use
useOptimistic without having to manually wrap the action in a startTransition* it works with js disabled (progressive enhancement)
@West African Lion In that video, I see that the emoji is removed from the input but I went over the GitHub code and I can't see where that is coming from.
i think that's due to the
key in the <main> tag. when the form is submitted, todos[0]?.id changes, which forces a remount of the <main> tag hence clearing the form@joulev yeah looks good, though i'd do wrap the <Button> in a form and use a form action [with `.bind` to bind the `note` variable](<https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#passing-additional-arguments>) instead. it has some benefits over simply calling the action:
* you have access to `useFormStatus`, no longer having to handle loading state manually for example
* you can use `useOptimistic` without having to manually wrap the action in a `startTransition`
* it works with js disabled (progressive enhancement)
West African LionOP
I'll look into that; thank you! Really trying to get the hang of the new server/client paradigm as I haven't played with it much.
@joulev i think that's due to the `key` in the `<main>` tag. when the form is submitted, `todos[0]?.id` changes, which forces a *remount* of the `<main>` tag hence clearing the form
West African LionOP
Interesting! I've been knee-deep in trying to understand the "industry way" to do this, but it seems like it must be a client component if I want to reset the form.
Was reading this:
https://sabin.dev/blog/how-to-clear-your-forms-when-using-server-actions-in-nextjs
Was reading this:
https://sabin.dev/blog/how-to-clear-your-forms-when-using-server-actions-in-nextjs
@joulev i think that's due to the `key` in the `<main>` tag. when the form is submitted, `todos[0]?.id` changes, which forces a *remount* of the `<main>` tag hence clearing the form
West African LionOP
That's sneaky! Is that the way it should be handled?
<main key={todos[0]?.id}>@West African Lion That's sneaky! Is that the way it should be handled?
`<main key={todos[0]?.id}>`
that way is not applicable in all cases imo. you don't always have a variable that is guaranteed to change following the submission.
form.reset() in a client component is still a very valid way, nothing wrong with that.West African LionOP
I was under the impression I was trying to avoid as much client components as I could
So is this not true, or is this a case of something that needs to be client since the form is on the browser?
That's an interesting way of using bind that I've never seen. I remember using classes and needing to bind functions for the instance, but this is new to me! I'll look into it more
const updateUserWithId = updateUser.bind(null, userId)@West African Lion I was under the impression I was trying to avoid as much client components as I could
just think of it like this: can it be done with purely html and css?
if yes, it can be done in purely server components. otherwise a client-side logic has to be involved at some point.
clearing form is not possible with just html and css (you can reload the page to clear but that doesn't count). so a client component is needed. in the
so yeah, no need to avoid client components. use them where they are needed.
if yes, it can be done in purely server components. otherwise a client-side logic has to be involved at some point.
clearing form is not possible with just html and css (you can reload the page to clear but that doesn't count). so a client component is needed. in the
key example, a client component wasn't used because client-side react automatically takes note of the key change (so there are still client-side logic involved), but that's not always possible.so yeah, no need to avoid client components. use them where they are needed.
@West African Lion That's an interesting way of using bind that I've never seen. I remember using classes and needing to bind functions for the instance, but this is new to me! I'll look into it more
`const updateUserWithId = updateUser.bind(null, userId)`
in your case it would be something like
"use client"
function DeleteNoteButton({ note }) {
const action = deleteNote.bind(null, note);
return (
<form action={action}>
<Button type="submit">Delete</Button>
</form>
);
}
const Notes = ({
notes,
}: {
notes: Database["public"]["Tables"]["notes"]["Row"][];
}) => {
return (
<Accordion className="w-96">
{notes.map((note) => (
<AccordionPanel key={note.id}>
<AccordionTitle>{note.title}</AccordionTitle>
<AccordionContent>
<div>{note.content}</div>
<div>Tags: {note.tags?.join(", ")}</div>
<DeleteNoteButton note={note} />
</AccordionContent>
</AccordionPanel>
))}
</Accordion>
);
};West African LionOP
So it still uses client logic, just automatically executed one from React? Meaning it is still something that needs a client component?
in the key example, a client component wasn't used because client-side react automatically takes note of the key change (so there are still client-side logic involved), but that's not always possible.
@West African Lion So it still uses client logic, just automatically executed one from React? Meaning it is still something that needs a client component?
> in the key example, a client component wasn't used because client-side react automatically takes note of the key change (so there are still client-side logic involved), but that's not always possible.
client side react listens to the
key changes of all components and automatically remounts when the key value is updated. so in this particular case you don't need client components to still do something on the client. this is not always possible. most of the time, you will need a client component here and call form.reset() explicitly.for example a contact form, after submission there are no variable changes in the page. so you have to use a client component to force-clear, because you don't have anything to put in the
keyWest African LionOP
Ahhhhhhh! I get it now, that is a sneaky trick they did there
Don't know that I agree with that kind of trick for what should be an intro example. That's just my view I guess 🤷♂️
yeah i agree too honestly. i have never seen that being used anywhere, and i don't use that trick. if they don't want to use a client component, at least they should be explaining how the form clear worked.
West African LionOP
I mean, in a high-level guide for people who know what they are doing, you don't need to explain everything. When your target audience is people new to these concepts, it seems like they should have gone with a clear solution. Then again, that could just be the idiot in me wanted something easier lol
Regardless, you have shed so much light on this whole thing! Thank you so so much ❤️
I feel like I understand the structure a little better now
I might try to trim some fat from this project and upload the whole thing to see if I can get some reviews of it before I move to something more complicated. Thank you so so much ❤️
you're welcome