Upload multiples files to an entry after its creation (and how to add a caption ?)

System Information
  • Strapi Version: 3.2.3
  • Operating System: alpine3.12
  • Database: postgres 13
  • Node Version: node 12.19
  • NPM Version: ?
  • Yarn Version:

Hello, community,

I am trying to upload multiples files to an entry already created.

async addImagesToPost(images, postId) {
  const bodyFormData = new FormData()

  bodyFormData.append('ref', 'posts')
  bodyFormData.append('refId', postId)
  bodyFormData.append('field', 'images')
  images.forEach(({ file }) => bodyFormData.append(`files.images`, file, file.name))

  try {
    // the client is an axios instance.
    return await client.post('/upload', bodyFormData)
  } catch (error) {
    console.error("error while adding images to post", error)
    return error.response
  }
}

This is the code I am using and it doesn’t work. Even if instead of using files.images I am using files[] (which a standard look at here in the example) or 'files.' + index it does not works.

If I am uploading a single file it works bodyFormData.append(files, images[0].file, images[0].name)

They said how to upload multiples files at the same time as creating the entry but not when we want to add some files to an entry.

At the same time in the documentation there no mention of how to add a caption for instance on an image.

If somebody has the answer it will be great :slight_smile:

Everything looks fine, expect:

It should be just files, without .images

images.forEach(({ file }) => bodyFormData.append(`files`, file, file.name))

I don’t know if you are uploading from backend or frontend, or if you set the headers to the axios instance, but if you use axios on the backend, then I want to mention that you need to use getHeaders() in Node.js because Axios doesn’t automatically set the multipart form boundary in Node.

So for the backend, the correct axios request will be:

return await client.post('/upload', bodyFormData,{
    headers: {
      ...data.getHeaders(),
    },
  })
1 Like

I am from the client-side. Okay so just uploading to files works with multiples files too.
And for the caption, there is any way to add it? Or do I need to create a route specifically for updating an image id with a caption?

Yes, you can add them, in fileInfo:

bodyFormData.append('fileInfo', '{"caption":"caption text","alternativeText":"alternative text"}');

Currently, there is no way to add caption and alternativeText for multiple files, you can send it only for a single file. If you send it with multiple files then only the first one will get them.

I would recommend sending each file individually to the /upload path, something like:

   images.forEach(({ file }) => {
        const bodyFormData = new FormData()
        bodyFormData.append('ref', 'posts')
        bodyFormData.append('refId', postId)
        bodyFormData.append('field', 'images')
        bodyFormData.append(`files`, file)
        bodyFormData.append('fileInfo', `{"caption":"${file.caption}","alternativeText":"${file.alternativeText}","name":"${file.name}"}`);
        client.post('/upload', bodyFormData)
    })
3 Likes

Amazing, you should add it to the documentation! It’s a must-have information :slight_smile:

1 Like

Yeah, a lot of things are not documented yet. Also a lot of cool things are made by contributors and not all of them update the documentation.

I am doing the same
Collection: article
field: image

new Image is being uploaded but the id is not being updated in article entry nor the image caption and alternative text.

Actually you can send multiple fileInfo objects (1 for each file you are uploading). Works great.

Can you show an example of multiple fileInfo objects with captions? I’m currently trying to do it and not having any luck

I am not using Javascript for my client code but here is an example that should be close.

Also, don’t you need the full api name for the ref? Instead of ‘posts’, it would be ‘api::post.post’.
Cool if that works for you.

 let fileInfos = [];
    const bodyFormData = new FormData()
    bodyFormData.append('ref', 'posts')
    bodyFormData.append('refId', postId)
    bodyFormData.append('field', 'images')   
   images.forEach(({ file }) => {
        bodyFormData.append(`files`, file)
        fileInfos.push({"caption": file.caption, "alternativeText": file.alternativeText, "name": file.name})
    })
    bodyFormData.append('fileInfo', JSON.stringify(fileInfos));
    client.post('/upload', bodyFormData)

Hmm, I couldn’t get it working. I didn’t really need it to work but was testing something out.

Can I ask you something slightly different? When I’m uploading images, I do it with a custom controller while the entry is created. The code you have above is after the entry is created and you reference it with the refId. Should I be doing this also? The reason I ask is when I delete an entry the images accciated are not being deleted from the media library.

const entity = await strapi.service("api::listing.listing").create({
      data: {
        contact_firstname: listing.contact_firstname,
        contact_lastname: listing.contact_lastname,
        contact_phone: listing.contact_phone,
        contact_email: listing.contact_email,
        contact_city: listing.contact_city,
        contact_state: listing.contact_state,
        title: listing.title,
        price: listing.price,
        description: listing.description,
        category: listing.category,
        featured: listing.featured,
        publishedAt: listing.publishedAt,
        session_id: session.id,
      },
      files,
    });

Hey @thanneman
To answer your questions:

You don’t necessarily need a custom controller to add media files during entity creation. As long as you set the form data fields from the Strapi docs (being sure to start all of the file objects with ‘files.’ And specify the field that the belong to using the input field.

You are right that the code I showed was when adding media files to and existing entry. No need to specify these on creating a new entry.

Strapi does not automatically remove the media files associated with a content type record when the record is deleted. I created a util service (see below) that I call from a custom controller that overrides the default delete method and calls a util method to delete any related files

I too have created custom code (a util service, and custom plugin extension code for user registration) that handles several file upload challenges like:

Uploading images (like an Avatar) during user registration

Passing fileInfo information for any files

Deleting files when a content type that has associated media fields is deleted (No, Strapi doesn’t automatically do this)

The ability to update fileInfo fields for an existing media file (without have to re-upload the files).