IdoPesok / zsa

Home Page:https://zsa.vercel.app

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Facing trouble with FormData.

Kiranism opened this issue · comments

I would like to know how to deal with formData when using the useServerAction hook in the onSubmit of a form. I am sharing a common Zod schema between the client and server. When dealing with an array of objects, I stringify them and use formData.append. However, the createServerAction() .input(POST_SCHEMA, { type: 'formData' }) validates the input against the Post schema, causing a Zod error since the types are different. What is the best way to handle this?

Hi - happy to help. Can you share some code examples of this so I can get a better picture of the problem and provide a more specific solution?

Something I think would help is rather than stringifying the objects in the form data, you can use binding to pass them normally.

Hi - happy to help. Can you share some code examples of this so I can get a better picture of the problem and provide a more specific solution?

Since I'm dealing with files, I need to convert the data to formData. When I do that, the validation fails in the input() function because it compares with the formData object.

Can you share the input schema you are using? With more details on how to replicate, I can help come up with the answer.

Can you share the input schema you are using? With more details on how to replicate, I can help come up with the answer.

yea sure.
zsa

Hi, can you try this:

export const POST_SCHEMA = z.object({
  title: z.string()
    .min(3, { message: "Blog title must be at least 3 characters" }),
  slug: z.string()
    .min(3, { message: "Blog slug must be at least 3 characters" }),
  content: z.string()
    .min(3, { message: "Blog content must be at least 3 characters" }),
  categories: z.array(z.object({ label: z.string(), values: z.string() })).refine((value) => value.length > 0, {
    message: "Please select a category",
  }),
  images: z.array(z.instanceof(File)),
  featured: z.boolean(),
  published: z.boolean(),
});
export const createPost = isAdminProcedure
  .input(POST_SCHEMA)
  .mutation(async ({ input, ctx }) => {
    await savePostToDB(input);
    return {
      success: true
    };
  });
const onSubmit = async (values: POST_SCHEMA_VALUES) => {
  const formData = new FormData();
  for (let i = 0; i < values.images.length; i++) {
    formData.append('images', values.images[i].file, values.images[i].name);
  }
  const { images, ...rest } = values;
  await execute(formData, rest);
};

Make sure to include an image name as the third argument so it encodes as a file.

Note, I may have not copied the schema perfectly from the image. But the TLDR is you only need to pass the images through the form data, and can pass the rest as normal JSON through the second argument in execute. And make sure you are including a name for the file in the third argument of formData.append

Note, I may have not copied the schema perfectly from the image. But the TLDR is you only need to pass the images through the form data, and can pass the rest as normal JSON through the second argument in execute. And make sure you are including a name for the file.

fine, but the boolean fields also throwing the zod error of [ "Expected boolean, received string" ]

Are you passing the booleans in the form data or in the second argument of the execute function?

Are you passing the booleans in the form data or in the second argument of the execute function?

in the formdata.

Can you try passing them in the second argument as JSON?

Can you try passing them in the second argument as JSON? Otherwise they will be strings.

Well, that works.

Note, I may have not copied the schema perfectly from the image. But the TLDR is you only need to pass the images through the form data, and can pass the rest as normal JSON through the second argument in execute. And make sure you are including a name for the file in the third argument of formData.append

So, this is the proper way to do things right? Thanks, man, for your help.

Of course! Happy to help. W.r.t. proper way of doing things, I would say you can generally pass everything through form data if its convenient, however there are some quirks to form data (like the boolean thing). You already had things in JSON with values so it was easy to just pass that along as JSON and only pass the images in form data. Files must be passed in form data so they can be encoded correctly to go over the network.

I would recommend reading through this doc page and using the strategy that is most intuitive to you. I know there are a lot so it can be confusing which one is "correct", but they are all "correct" and it's a matter of what clicks in your head the best.