Search code examples
javascriptreactjsnext.jsmultipartform-datapocketbase

How to upload multiple files with fields at once with FormData?


I have a pocketbase collection with name, image and order fields. I am trying to upload all the images with a unique name and images using FormData in parallel.

Here's is my code:

export default function AddPhotosAdmin({ photosDb }: PhotoDisplayProps) {

    async function addPhotos(formData: FormData) {
        'use server'

        const name = formData.get("name") as string
        let order = 0
        const dataPost = new FormData
        const Image_array = Array.from(formData.getAll("Image"))
        Image_array.map((image) => {
            dataPost.append('name', name)
            dataPost.append('Image', image)
            dataPost.append('order', (order++).toString())
        })
        
        const pb = new PocketBase(process.env.DB_ADDR);
        pb.collection('Photos').create(dataPost);
        revalidatePath("/Photos")
    }
    
    return (
        <div>
            <form action={addPhotos} className="text-black">

                <input name="name" />

                <input
                    type="file"
                    name="Image"
                    required
                    multiple
                    accept="image/*"
                    className="text-white"
                ></input>

                <input type="submit" className="text-white" value="Créer" />
            </form>
        </div>
    )

I have tried a lot of ways to try and send all the data at once and to no success. Using a loop, POST is auto cancelled and appears not the most suitable choice.


Solution

  • I suggest using Promise.all() to handle multiple asynchronous operations concurrently. Array.map() does not ensure that each upload completes before moving to the next one. i edited the code so it uses Promise, hope this helps you.

    interface PhotoDisplayProps {
      photosDb: any; 
    }
    export default function AddPhotosAdmin({ photosDb }: PhotoDisplayProps) {
      async function addPhotos(event: React.FormEvent<HTMLFormElement>) {
        event.preventDefault();
        const formData = new FormData(event.currentTarget);
        const name = formData.get("name") as string;
        const pb = new PocketBase(process.env.DB_ADDR);
        const imageFiles = formData.getAll("Image");
        const dataPromises = Array.from(imageFiles).map(async (imageFile, index) => {
          const order = index; 
          const dataPost = new FormData();
          dataPost.append("name", name);
          dataPost.append("Image", imageFile);
          dataPost.append("order", order.toString());
          await pb.collection("Photos").create(dataPost);
        });
    
        try {
    
          await Promise.all(dataPromises);
          revalidatePath("/Photos");
        } catch (error) {
          console.error("Error uploading photos:", error);
        }
      }
    
      return (
        <div>
          <form onSubmit={addPhotos} className="text-black">
            <input name="name" />
            <input
              type="file"
              name="Image"
              required
              multiple
              accept="image/*"
              className="text-white"
            ></input>
            <input type="submit" className="text-white" value="Créer" />
          </form>
        </div>
      );
    }